完成取色器的重构

master
yutent 2023-11-29 11:42:01 +08:00
parent eca1a50619
commit d111e67efc
1 changed files with 86 additions and 66 deletions

View File

@ -12,7 +12,6 @@ import {
Component, Component,
outsideClick, outsideClick,
clearOutsideClick, clearOutsideClick,
nextTick,
offset, offset,
styleMap styleMap
} from 'wkit' } from 'wkit'
@ -23,19 +22,19 @@ const ROOT = document.documentElement
// H: 色相, S: 饱和度, B/V: 亮度 // H: 色相, S: 饱和度, B/V: 亮度
export function hsb2rgb(hsb) { export function hsb2rgb(hsb) {
var h = hsb.h let h = hsb.h
var s = Math.round((hsb.s * 255) / 100) let s = Math.round((hsb.s * 255) / 100)
var v = Math.round((hsb.b * 255) / 100) let v = Math.round((hsb.b * 255) / 100)
var r = 0 let r = 0
var g = 0 let g = 0
var b = 0 let b = 0
if (s === 0) { if (s === 0) {
r = g = b = v r = g = b = v
} else { } else {
var t1 = v let t1 = v
var t2 = ((255 - s) * v) / 255 let t2 = ((255 - s) * v) / 255
var t3 = ((t1 - t2) * (h % 60)) / 60 let t3 = ((t1 - t2) * (h % 60)) / 60
// //
if (h === 360) { if (h === 360) {
@ -75,33 +74,51 @@ export function hsb2rgb(hsb) {
return { r, g, b } return { r, g, b }
} }
export function rgb2hex({ r, g, b }) { export function rgb2hex({ r, g, b }, a) {
return [r, g, b].map(it => it.toString(16).padStart(2, '0')).join('') let hex = [r, g, b].map(it => it.toString(16).padStart(2, '0')).join('')
if (a !== void 0) {
hex += (~~((a / 100) * 255)).toString(16)
}
return hex
} }
export function hex2rgb(hex) { export function hex2rgb(hex) {
var r, g, b let r, g, b, a
hex = hex.replace(/^#/, '').split('') hex = hex.replace(/^#/, '')
if (hex.length === 3) { switch (hex.length) {
r = parseInt(hex[0] + hex[0], 16) case 3:
g = parseInt(hex[1] + hex[1], 16) case 4:
b = parseInt(hex[2] + hex[2], 16) r = hex[0].repeat(2)
} else { g = hex[1].repeat(2)
r = parseInt(hex[0] + hex[1], 16) b = hex[2].repeat(2)
g = parseInt(hex[2] + hex[3], 16) a = (hex[3] || 'f').repeat(2)
b = parseInt(hex[4] + hex[5], 16)
break
case 6:
case 8:
r = hex.slice(0, 2)
g = hex.slice(2, 4)
b = hex.slice(4, 6)
a = hex.slice(6, 8) || 'ff'
break
} }
return { r, g, b } r = parseInt(r, 16)
g = parseInt(g, 16)
b = parseInt(b, 16)
a = ~~((parseInt(a, 16) * 100) / 255)
return { r, g, b, a }
} }
export function rgb2hsb({ r, g, b }) { export function rgb2hsb({ r, g, b }) {
var hsb = { h: 0, s: 0, b: 0 } let hsb = { h: 0, s: 0, b: 0 }
var max = Math.max(r, g, b) let max = Math.max(r, g, b)
var min = Math.min(r, g, b) let min = Math.min(r, g, b)
var delta = max - min let delta = max - min
hsb.b = max hsb.b = max
hsb.s = max === 0 ? 0 : (delta * 255) / max hsb.s = max === 0 ? 0 : (delta * 255) / max
@ -139,10 +156,8 @@ class Color extends Component {
type: String, type: String,
default: '', default: '',
observer(val) { observer(val) {
if (this.#show) {
this.#calc(val) this.#calc(val)
} }
}
}, },
disabled: false disabled: false
} }
@ -154,8 +169,8 @@ class Color extends Component {
} }
.container { .container {
position: relative; position: relative;
width: 32px; width: var(--wc-color-size, 32px);
height: 32px; height: var(--wc-color-size, 32px);
-webkit-user-select: none; -webkit-user-select: none;
user-select: none; user-select: none;
} }
@ -215,7 +230,7 @@ class Color extends Component {
position: absolute; position: absolute;
z-index: 1; z-index: 1;
left: 0; left: 0;
top: 38px; top: var(--wc-color-size, 32px);
width: 310px; width: 310px;
padding: 5px; padding: 5px;
background: var(--color-plain-1); background: var(--color-plain-1);
@ -378,7 +393,17 @@ class Color extends Component {
} }
} }
`, `,
css`
:host([size='small']) {
.container {
width: 24px;
height: 24px;
}
.color-panel {
top: 24px;
}
}
`,
css` css`
:host([disabled]) { :host([disabled]) {
opacity: 0.6; opacity: 0.6;
@ -402,41 +427,38 @@ class Color extends Component {
#y = 0 // 场景触点的Y坐标 #y = 0 // 场景触点的Y坐标
#ht = 0 // 颜色池的触点坐标 #ht = 0 // 颜色池的触点坐标
#at = 100 // 透明度条的触点坐标 #at = 100 // 透明度条的触点坐标
#sceneBg = '#ff0000' #sceneBg = '#000000'
#alphaBg = '#ff0000' #alphaBg = '#000000'
#cache = { #rgba = { r: 0, g: 0, b: 0, a: 100 }
hsb: { h: 0, s: 100, b: 100 }, #hsb = { h: 0, s: 100, b: 100 }
rgba: { r: 255, g: 0, b: 0, a: 100 }
}
#calc(val) { #calc(val) {
var isHex let isHex
var rgb
val = val.toLowerCase() val = val.toLowerCase()
if (!val) { if (!val || val === this.#value) {
return return
} }
isHex = /^#[0-9a-f]{3,6}$/.test(val) isHex = /^#[0-9a-f]{3,8}$/.test(val)
if (isHex) { if (isHex) {
Object.assign(this.#cache.rgba, hex2rgb(val), { a: 100 }) Object.assign(this.#rgba, hex2rgb(val))
} else { } else {
var res = val.match(/rgba?\((\d+),\s*?(\d+),\s*?(\d+)[,\s]*?([\d\.]+)?\)/) let res = val.match(/rgba?\((\d+),\s*?(\d+),\s*?(\d+)[,\s]*?([\d\.]+)?\)/)
if (res) { if (res) {
this.#cache.rgba = { r: +res[1], g: +res[2], b: +res[3], a: 100 } this.#rgba = { r: +res[1], g: +res[2], b: +res[3], a: 100 }
if (res[4] !== undefined) { if (res[4] !== undefined) {
this.#cache.rgba.a = ~~(res[4] * 100) this.#rgba.a = ~~(res[4] * 100)
} }
} else { } else {
return return
} }
} }
this.#cache.hsb = rgb2hsb(this.#cache.rgba) this.#hsb = rgb2hsb(this.#rgba)
} }
toggleColorPanel() { toggleColorPanel() {
@ -449,35 +471,31 @@ class Color extends Component {
// 透明度变化 // 透明度变化
#changeAlpha(ev) { #changeAlpha(ev) {
let a = +ev.target.value this.#rgba.a = +ev.target.value
let { r, g, b } = this.#cache.rgba
this.#cache.rgba.a = a
this.#updateView() this.#updateView()
} }
// 色彩池变化 // 色彩池变化
#changeHue(h) { #changeHue(h) {
h = h < 0 ? 0 : h > 360 ? 360 : h h = h < 0 ? 0 : h > 360 ? 360 : h
let { s, b } = this.#cache.hsb let { s, b } = this.#hsb
let rgba = this.#cache.rgba let rgba = this.#rgba
let hsb = { h, s, b } let hsb = { h, s, b }
Object.assign(rgba, hsb2rgb(hsb)) Object.assign(rgba, hsb2rgb(hsb))
this.#cache.hsb = hsb this.#hsb = hsb
this.#cache.rgba = rgba this.#rgba = rgba
this.#updateView() this.#updateView()
} }
// //
#changeColor(x, y) { #changeColor(x, y) {
let { hsb, rgba } = this.#cache let hsb = this.#hsb
let rgba = this.#rgba
hsb.s = ~~((100 * x) / 280) hsb.s = ~~((100 * x) / 280)
hsb.b = ~~((100 * (180 - y)) / 180) hsb.b = ~~((100 * (180 - y)) / 180)
Object.assign(rgba, hsb2rgb(hsb)) Object.assign(rgba, hsb2rgb(hsb))
this.#cache.hsb = hsb
this.#cache.rgba = rgba
this.#updateView() this.#updateView()
} }
@ -520,7 +538,7 @@ class Color extends Component {
bind(DOC, 'mouseup', _ => unbind(DOC, 'mousemove', callback), EV_OPTION) bind(DOC, 'mouseup', _ => unbind(DOC, 'mousemove', callback), EV_OPTION)
} }
#close(clear) { #close() {
if (this.#show) { if (this.#show) {
this.#show = false this.#show = false
this.#calc(this.value) this.#calc(this.value)
@ -531,13 +549,15 @@ class Color extends Component {
#submit() { #submit() {
this.value = this.#value this.value = this.#value
this.#close() this.#close()
this.$emit('change', { data: this.#value }) this.$emit('input')
this.$emit('change')
} }
#updateView() { #updateView() {
var { hsb, rgba } = this.#cache let hsb = this.#hsb
var sceneBg, color, alphaBg let rgba = this.#rgba
var x, y let sceneBg, color, alphaBg
let x, y
x = Math.ceil((hsb.s * 280) / 100) x = Math.ceil((hsb.s * 280) / 100)
y = 180 - Math.ceil((hsb.b * 180) / 100) y = 180 - Math.ceil((hsb.b * 180) / 100)
@ -618,7 +638,7 @@ class Color extends Component {
<section class="input-box"> <section class="input-box">
<input class="input focus" :value=${this.#value} maxlength="25" /> <input class="input focus" :value=${this.#value} maxlength="25" />
<a class="clear" @click=${_ => this.#close(true)}>清除</a> <a class="clear" @click=${this.#close}>取消</a>
<a tabindex="0" class="submit focus" @click=${this.#submit}>确定</a> <a tabindex="0" class="submit focus" @click=${this.#submit}>确定</a>
</section> </section>
</div> </div>