2023-03-23 19:42:15 +08:00
|
|
|
/**
|
2023-03-27 19:34:30 +08:00
|
|
|
* {color组件}
|
2023-03-23 19:42:15 +08:00
|
|
|
* @author chensbox <chensbox@foxmail.com>
|
|
|
|
* @date 2023/03/20 15:17:25
|
|
|
|
*/
|
|
|
|
|
|
|
|
import {
|
|
|
|
css,
|
|
|
|
html,
|
|
|
|
bind,
|
|
|
|
unbind,
|
|
|
|
Component,
|
|
|
|
outsideClick,
|
2023-03-27 10:26:57 +08:00
|
|
|
clearOutsideClick,
|
2023-11-24 18:38:06 +08:00
|
|
|
offset,
|
|
|
|
styleMap
|
2023-05-25 17:00:17 +08:00
|
|
|
} from 'wkit'
|
2023-03-23 19:42:15 +08:00
|
|
|
|
2023-11-24 18:38:06 +08:00
|
|
|
const EV_OPTION = { once: true }
|
|
|
|
const DOC = document
|
|
|
|
const ROOT = document.documentElement
|
|
|
|
|
2023-03-23 19:42:15 +08:00
|
|
|
// H: 色相, S: 饱和度, B/V: 亮度
|
|
|
|
export function hsb2rgb(hsb) {
|
2023-11-29 11:42:01 +08:00
|
|
|
let h = hsb.h
|
|
|
|
let s = Math.round((hsb.s * 255) / 100)
|
|
|
|
let v = Math.round((hsb.b * 255) / 100)
|
|
|
|
let r = 0
|
|
|
|
let g = 0
|
|
|
|
let b = 0
|
2023-03-23 19:42:15 +08:00
|
|
|
|
|
|
|
if (s === 0) {
|
|
|
|
r = g = b = v
|
|
|
|
} else {
|
2023-11-29 11:42:01 +08:00
|
|
|
let t1 = v
|
|
|
|
let t2 = ((255 - s) * v) / 255
|
|
|
|
let t3 = ((t1 - t2) * (h % 60)) / 60
|
2023-03-23 19:42:15 +08:00
|
|
|
|
|
|
|
//
|
|
|
|
if (h === 360) {
|
|
|
|
h = 0
|
|
|
|
}
|
|
|
|
|
|
|
|
if (h < 60) {
|
|
|
|
r = t1
|
|
|
|
g = t2 + t3
|
|
|
|
b = t2
|
|
|
|
} else if (h < 120) {
|
|
|
|
r = t1 - t3
|
|
|
|
g = t1
|
|
|
|
b = t2
|
|
|
|
} else if (h < 180) {
|
|
|
|
r = t2
|
|
|
|
g = t1
|
|
|
|
b = t2 + t3
|
|
|
|
} else if (h < 240) {
|
|
|
|
r = t2
|
|
|
|
g = t1 - t3
|
|
|
|
b = t1
|
|
|
|
} else if (h < 300) {
|
|
|
|
r = t2 + t3
|
|
|
|
g = t2
|
|
|
|
b = t1
|
|
|
|
} else if (h < 360) {
|
|
|
|
r = t1
|
|
|
|
g = t2
|
|
|
|
b = t1 - t3
|
|
|
|
}
|
|
|
|
}
|
|
|
|
r = Math.round(r)
|
|
|
|
g = Math.round(g)
|
|
|
|
b = Math.round(b)
|
|
|
|
|
|
|
|
return { r, g, b }
|
|
|
|
}
|
|
|
|
|
2023-11-29 11:42:01 +08:00
|
|
|
export function rgb2hex({ r, g, b }, a) {
|
|
|
|
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
|
2023-03-23 19:42:15 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
export function hex2rgb(hex) {
|
2023-11-29 11:42:01 +08:00
|
|
|
let r, g, b, a
|
|
|
|
|
|
|
|
hex = hex.replace(/^#/, '')
|
|
|
|
|
|
|
|
switch (hex.length) {
|
|
|
|
case 3:
|
|
|
|
case 4:
|
|
|
|
r = hex[0].repeat(2)
|
|
|
|
g = hex[1].repeat(2)
|
|
|
|
b = hex[2].repeat(2)
|
|
|
|
a = (hex[3] || 'f').repeat(2)
|
|
|
|
|
|
|
|
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
|
2023-03-23 19:42:15 +08:00
|
|
|
}
|
|
|
|
|
2023-11-29 11:42:01 +08:00
|
|
|
r = parseInt(r, 16)
|
|
|
|
g = parseInt(g, 16)
|
|
|
|
b = parseInt(b, 16)
|
|
|
|
a = ~~((parseInt(a, 16) * 100) / 255)
|
|
|
|
|
|
|
|
return { r, g, b, a }
|
2023-03-23 19:42:15 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
export function rgb2hsb({ r, g, b }) {
|
2023-11-29 11:42:01 +08:00
|
|
|
let hsb = { h: 0, s: 0, b: 0 }
|
|
|
|
let max = Math.max(r, g, b)
|
|
|
|
let min = Math.min(r, g, b)
|
|
|
|
let delta = max - min
|
2023-03-23 19:42:15 +08:00
|
|
|
|
|
|
|
hsb.b = max
|
|
|
|
hsb.s = max === 0 ? 0 : (delta * 255) / max
|
|
|
|
|
|
|
|
if (hsb.s === 0) {
|
|
|
|
hsb.h = -1
|
|
|
|
} else {
|
|
|
|
if (r === max) {
|
|
|
|
hsb.h = (g - b) / delta
|
|
|
|
} else if (g === max) {
|
|
|
|
hsb.h = 2 + (b - r) / delta
|
|
|
|
} else {
|
|
|
|
hsb.h = 4 + (r - g) / delta
|
|
|
|
}
|
|
|
|
}
|
|
|
|
hsb.h *= 60
|
|
|
|
|
|
|
|
if (hsb.h < 0) {
|
|
|
|
hsb.h += 360
|
|
|
|
}
|
|
|
|
|
|
|
|
hsb.s *= 100 / 255
|
|
|
|
hsb.b *= 100 / 255
|
|
|
|
|
|
|
|
return hsb
|
|
|
|
}
|
|
|
|
|
|
|
|
export function hex2hsb(hex) {
|
|
|
|
return rgb2hsb(hex2rgb(hex))
|
|
|
|
}
|
|
|
|
|
|
|
|
class Color extends Component {
|
|
|
|
static props = {
|
|
|
|
value: {
|
|
|
|
type: String,
|
|
|
|
default: '',
|
|
|
|
observer(val) {
|
2023-11-29 11:42:01 +08:00
|
|
|
this.#calc(val)
|
2023-03-23 19:42:15 +08:00
|
|
|
}
|
|
|
|
},
|
2023-11-24 18:38:06 +08:00
|
|
|
disabled: false
|
2023-03-23 19:42:15 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
static styles = [
|
|
|
|
css`
|
|
|
|
:host {
|
|
|
|
display: inline-flex;
|
|
|
|
}
|
2023-11-24 18:38:06 +08:00
|
|
|
.container {
|
2023-03-23 19:42:15 +08:00
|
|
|
position: relative;
|
2023-11-29 11:42:01 +08:00
|
|
|
width: var(--wc-color-size, 32px);
|
|
|
|
height: var(--wc-color-size, 32px);
|
2023-11-24 18:55:09 +08:00
|
|
|
-webkit-user-select: none;
|
|
|
|
user-select: none;
|
2023-03-23 19:42:15 +08:00
|
|
|
}
|
|
|
|
.alpha-bg {
|
|
|
|
background: linear-gradient(
|
|
|
|
45deg,
|
|
|
|
var(--color-grey-1) 25%,
|
|
|
|
transparent 25%,
|
|
|
|
transparent 75%,
|
|
|
|
var(--color-grey-1) 75%,
|
|
|
|
var(--color-grey-1)
|
|
|
|
),
|
|
|
|
linear-gradient(
|
|
|
|
45deg,
|
|
|
|
var(--color-grey-1) 25%,
|
|
|
|
transparent 25%,
|
|
|
|
transparent 75%,
|
|
|
|
var(--color-grey-1) 75%,
|
|
|
|
var(--color-grey-1)
|
|
|
|
);
|
|
|
|
background-size: 12px 12px;
|
|
|
|
background-position: 0 0, 6px 6px;
|
|
|
|
}
|
2023-11-24 18:55:09 +08:00
|
|
|
|
|
|
|
.focus {
|
|
|
|
transition: box-shadow 0.15s linear;
|
|
|
|
|
|
|
|
&:focus-within {
|
|
|
|
box-shadow: 0 0 0 2px var(--color-plain-a);
|
|
|
|
}
|
|
|
|
}
|
2023-03-23 19:42:15 +08:00
|
|
|
`,
|
|
|
|
// 预览
|
|
|
|
css`
|
|
|
|
.preview {
|
|
|
|
display: flex;
|
|
|
|
width: 100%;
|
|
|
|
height: 100%;
|
2023-11-24 18:38:06 +08:00
|
|
|
border: 1px solid var(--color-grey-2);
|
|
|
|
border-radius: 3px;
|
2023-03-23 19:42:15 +08:00
|
|
|
cursor: pointer;
|
|
|
|
|
|
|
|
span {
|
|
|
|
width: 100%;
|
|
|
|
height: 100%;
|
|
|
|
border: 3px solid #fff;
|
2023-11-24 18:38:06 +08:00
|
|
|
border-radius: 3px;
|
|
|
|
background: var(--value);
|
2023-03-23 19:42:15 +08:00
|
|
|
outline: none;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
`,
|
|
|
|
// .color-panel
|
|
|
|
css`
|
|
|
|
.color-panel {
|
2023-11-24 18:38:06 +08:00
|
|
|
display: var(--show, none);
|
2023-03-23 19:42:15 +08:00
|
|
|
position: absolute;
|
2023-11-24 18:38:06 +08:00
|
|
|
z-index: 1;
|
2023-03-23 19:42:15 +08:00
|
|
|
left: 0;
|
2023-11-29 11:42:01 +08:00
|
|
|
top: var(--wc-color-size, 32px);
|
2023-03-23 19:42:15 +08:00
|
|
|
width: 310px;
|
|
|
|
padding: 5px;
|
2023-11-24 18:55:09 +08:00
|
|
|
background: var(--color-plain-1);
|
|
|
|
box-shadow: 0 0 12px rgba(0, 0, 0, 0.3);
|
2023-03-23 19:42:15 +08:00
|
|
|
}
|
|
|
|
.dashboard {
|
|
|
|
display: flex;
|
|
|
|
justify-content: space-between;
|
|
|
|
|
|
|
|
.scene {
|
|
|
|
overflow: hidden;
|
|
|
|
position: relative;
|
|
|
|
width: 280px;
|
|
|
|
height: 180px;
|
2023-11-24 18:38:06 +08:00
|
|
|
background: linear-gradient(180deg, transparent, #000),
|
|
|
|
linear-gradient(90deg, #fff, transparent), var(--scene);
|
2023-03-23 19:42:15 +08:00
|
|
|
|
|
|
|
.thumb {
|
|
|
|
position: absolute;
|
2023-11-24 18:38:06 +08:00
|
|
|
z-index: 1;
|
|
|
|
left: var(--x);
|
|
|
|
top: var(--y);
|
2023-03-23 19:42:15 +08:00
|
|
|
width: 0;
|
|
|
|
height: 0;
|
|
|
|
|
|
|
|
&::after {
|
|
|
|
display: block;
|
|
|
|
width: 10px;
|
|
|
|
height: 10px;
|
2023-11-24 18:38:06 +08:00
|
|
|
border: 1px solid #fff;
|
2023-03-23 19:42:15 +08:00
|
|
|
border-radius: 50%;
|
|
|
|
background: rgba(32, 32, 32, 0.3);
|
|
|
|
transform: translate(-5px, -5px);
|
|
|
|
content: '';
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
.pool {
|
|
|
|
overflow: hidden;
|
|
|
|
position: relative;
|
|
|
|
width: 12px;
|
|
|
|
height: 180px;
|
|
|
|
background: linear-gradient(
|
|
|
|
to bottom,
|
|
|
|
#f00 0,
|
|
|
|
#ff0 17%,
|
|
|
|
#0f0 33%,
|
|
|
|
#0ff 50%,
|
|
|
|
#00f 67%,
|
|
|
|
#f0f 83%,
|
|
|
|
#f00
|
|
|
|
);
|
|
|
|
|
|
|
|
.thumb {
|
|
|
|
position: absolute;
|
|
|
|
left: 0;
|
2023-11-24 18:38:06 +08:00
|
|
|
top: var(--ht);
|
2023-03-23 19:42:15 +08:00
|
|
|
width: 12px;
|
|
|
|
height: 0;
|
|
|
|
|
|
|
|
&::after {
|
|
|
|
display: block;
|
|
|
|
width: 12px;
|
|
|
|
height: 12px;
|
2023-11-24 18:55:09 +08:00
|
|
|
border: 1px solid #888;
|
2023-03-23 19:42:15 +08:00
|
|
|
border-radius: 50%;
|
|
|
|
background: #fff;
|
|
|
|
transform: translateY(-6px);
|
|
|
|
content: '';
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
.alpha-box {
|
|
|
|
overflow: hidden;
|
|
|
|
position: relative;
|
|
|
|
width: 100%;
|
|
|
|
height: 12px;
|
|
|
|
margin: 12px 0;
|
|
|
|
|
|
|
|
.bar {
|
|
|
|
position: absolute;
|
|
|
|
left: 0;
|
|
|
|
top: 0;
|
|
|
|
width: 100%;
|
|
|
|
height: 12px;
|
2023-11-24 18:38:06 +08:00
|
|
|
background: linear-gradient(90deg, transparent, var(--alpha));
|
2023-03-23 19:42:15 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
.thumb {
|
|
|
|
position: absolute;
|
2023-11-24 18:38:06 +08:00
|
|
|
left: var(--at);
|
2023-03-23 19:42:15 +08:00
|
|
|
top: 0;
|
|
|
|
width: 0;
|
|
|
|
height: 12px;
|
|
|
|
|
|
|
|
&::after {
|
|
|
|
display: block;
|
|
|
|
width: 12px;
|
|
|
|
height: 12px;
|
2023-11-24 18:55:09 +08:00
|
|
|
border: 1px solid #888;
|
2023-03-23 19:42:15 +08:00
|
|
|
border-radius: 50%;
|
|
|
|
background: #fff;
|
|
|
|
transform: translateX(-6px);
|
|
|
|
content: '';
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
.alpha {
|
|
|
|
position: relative;
|
|
|
|
display: block;
|
|
|
|
width: 100%;
|
|
|
|
height: 12px;
|
|
|
|
opacity: 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
`,
|
|
|
|
css`
|
|
|
|
.input-box {
|
|
|
|
display: flex;
|
|
|
|
justify-content: space-between;
|
|
|
|
align-items: center;
|
|
|
|
padding: 6px 0;
|
2023-11-24 18:55:09 +08:00
|
|
|
font-size: 12px;
|
2023-03-23 19:42:15 +08:00
|
|
|
|
|
|
|
.input {
|
|
|
|
width: 200px;
|
|
|
|
height: 24px;
|
|
|
|
padding: 0 6px;
|
|
|
|
line-height: 22px;
|
2023-11-24 18:55:09 +08:00
|
|
|
font-family: monospace;
|
|
|
|
border: 1px solid var(--color-grey-2);
|
|
|
|
border-radius: 3px;
|
2023-03-23 19:42:15 +08:00
|
|
|
outline: none;
|
|
|
|
color: var(--color-dark-1);
|
|
|
|
|
|
|
|
&::placeholder {
|
|
|
|
color: var(--color-grey-1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
.clear,
|
|
|
|
.submit {
|
2023-11-24 18:55:09 +08:00
|
|
|
color: var(--color-dark-1);
|
2023-03-23 19:42:15 +08:00
|
|
|
cursor: pointer;
|
|
|
|
}
|
|
|
|
|
|
|
|
.submit {
|
|
|
|
padding: 2px 6px;
|
|
|
|
border-radius: 2px;
|
2023-11-24 18:55:09 +08:00
|
|
|
color: #fff;
|
2023-03-23 19:42:15 +08:00
|
|
|
background: var(--color-teal-2);
|
|
|
|
outline: none;
|
|
|
|
transition: box-shadow 0.15s linear, background 0.15s linear;
|
|
|
|
|
|
|
|
&:hover {
|
|
|
|
background: var(--color-teal-1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2023-11-24 18:38:06 +08:00
|
|
|
`,
|
2023-11-29 11:42:01 +08:00
|
|
|
css`
|
|
|
|
:host([size='small']) {
|
|
|
|
.container {
|
|
|
|
width: 24px;
|
|
|
|
height: 24px;
|
|
|
|
}
|
|
|
|
.color-panel {
|
|
|
|
top: 24px;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
`,
|
2023-11-24 18:38:06 +08:00
|
|
|
css`
|
|
|
|
:host([disabled]) {
|
|
|
|
opacity: 0.6;
|
|
|
|
|
|
|
|
.preview {
|
|
|
|
cursor: not-allowed;
|
|
|
|
|
|
|
|
&:focus-within {
|
|
|
|
box-shadow: unset;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2023-03-23 19:42:15 +08:00
|
|
|
`
|
|
|
|
]
|
|
|
|
|
2023-11-24 18:38:06 +08:00
|
|
|
#show = false
|
|
|
|
|
|
|
|
// 临时的value, 组件内的操作, 修改的是这个值, 避免直接修改value触发太多的计算
|
|
|
|
#value = ''
|
|
|
|
#x = 0 // 场景触点的X坐标
|
|
|
|
#y = 0 // 场景触点的Y坐标
|
|
|
|
#ht = 0 // 颜色池的触点坐标
|
|
|
|
#at = 100 // 透明度条的触点坐标
|
2023-11-29 11:42:01 +08:00
|
|
|
#sceneBg = '#000000'
|
|
|
|
#alphaBg = '#000000'
|
2023-11-24 18:38:06 +08:00
|
|
|
|
2023-11-29 11:42:01 +08:00
|
|
|
#rgba = { r: 0, g: 0, b: 0, a: 100 }
|
|
|
|
#hsb = { h: 0, s: 100, b: 100 }
|
2023-11-24 18:38:06 +08:00
|
|
|
|
2023-03-27 10:26:57 +08:00
|
|
|
#calc(val) {
|
2023-11-29 11:42:01 +08:00
|
|
|
let isHex
|
2023-03-27 10:26:57 +08:00
|
|
|
|
|
|
|
val = val.toLowerCase()
|
|
|
|
|
2023-11-29 11:42:01 +08:00
|
|
|
if (!val || val === this.#value) {
|
2023-03-27 10:26:57 +08:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2023-11-29 11:42:01 +08:00
|
|
|
isHex = /^#[0-9a-f]{3,8}$/.test(val)
|
2023-03-27 10:26:57 +08:00
|
|
|
|
|
|
|
if (isHex) {
|
2023-11-29 11:42:01 +08:00
|
|
|
Object.assign(this.#rgba, hex2rgb(val))
|
2023-03-27 10:26:57 +08:00
|
|
|
} else {
|
2023-11-29 11:42:01 +08:00
|
|
|
let res = val.match(/rgba?\((\d+),\s*?(\d+),\s*?(\d+)[,\s]*?([\d\.]+)?\)/)
|
2023-03-27 10:26:57 +08:00
|
|
|
if (res) {
|
2023-11-29 11:42:01 +08:00
|
|
|
this.#rgba = { r: +res[1], g: +res[2], b: +res[3], a: 100 }
|
2023-03-27 10:26:57 +08:00
|
|
|
if (res[4] !== undefined) {
|
2023-11-29 11:42:01 +08:00
|
|
|
this.#rgba.a = ~~(res[4] * 100)
|
2023-03-27 10:26:57 +08:00
|
|
|
}
|
|
|
|
} else {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-11-29 11:42:01 +08:00
|
|
|
this.#hsb = rgb2hsb(this.#rgba)
|
2023-03-27 10:26:57 +08:00
|
|
|
}
|
|
|
|
|
2023-03-23 19:42:15 +08:00
|
|
|
toggleColorPanel() {
|
2023-11-24 18:38:06 +08:00
|
|
|
if (this.disabled) {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
this.#show = true
|
2023-03-27 10:26:57 +08:00
|
|
|
this.#updateView()
|
2023-03-23 19:42:15 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
// 透明度变化
|
2023-11-24 18:38:06 +08:00
|
|
|
#changeAlpha(ev) {
|
2023-11-29 11:42:01 +08:00
|
|
|
this.#rgba.a = +ev.target.value
|
2023-03-23 19:42:15 +08:00
|
|
|
this.#updateView()
|
|
|
|
}
|
|
|
|
// 色彩池变化
|
2023-11-24 18:38:06 +08:00
|
|
|
#changeHue(h) {
|
|
|
|
h = h < 0 ? 0 : h > 360 ? 360 : h
|
2023-11-29 11:42:01 +08:00
|
|
|
let { s, b } = this.#hsb
|
|
|
|
let rgba = this.#rgba
|
2023-11-24 18:38:06 +08:00
|
|
|
let hsb = { h, s, b }
|
2023-03-23 19:42:15 +08:00
|
|
|
|
|
|
|
Object.assign(rgba, hsb2rgb(hsb))
|
|
|
|
|
2023-11-29 11:42:01 +08:00
|
|
|
this.#hsb = hsb
|
|
|
|
this.#rgba = rgba
|
2023-11-24 18:38:06 +08:00
|
|
|
|
|
|
|
this.#updateView()
|
|
|
|
}
|
|
|
|
//
|
|
|
|
#changeColor(x, y) {
|
2023-11-29 11:42:01 +08:00
|
|
|
let hsb = this.#hsb
|
|
|
|
let rgba = this.#rgba
|
2023-11-24 18:38:06 +08:00
|
|
|
hsb.s = ~~((100 * x) / 280)
|
|
|
|
hsb.b = ~~((100 * (180 - y)) / 180)
|
|
|
|
Object.assign(rgba, hsb2rgb(hsb))
|
2023-03-23 19:42:15 +08:00
|
|
|
|
|
|
|
this.#updateView()
|
|
|
|
}
|
|
|
|
|
2023-11-24 18:38:06 +08:00
|
|
|
#sceneMousedown(ev) {
|
|
|
|
let { x, y } = ev
|
|
|
|
let { left, top } = offset(ev.currentTarget)
|
|
|
|
let { scrollLeft, scrollTop } = ROOT
|
|
|
|
let _x = left - scrollLeft
|
|
|
|
let _y = top - scrollTop
|
|
|
|
|
|
|
|
this.#changeColor(x - _x, y - _y)
|
|
|
|
|
|
|
|
let callback = bind(DOC, 'mousemove', ({ x, y }) => {
|
|
|
|
x -= _x
|
|
|
|
y -= _y
|
|
|
|
|
|
|
|
x = x < 0 ? 0 : x > 280 ? 280 : x
|
|
|
|
y = y < 0 ? 0 : y > 180 ? 180 : y
|
|
|
|
|
|
|
|
this.#changeColor(x, y)
|
|
|
|
})
|
|
|
|
bind(DOC, 'mouseup', _ => unbind(DOC, 'mousemove', callback), EV_OPTION)
|
|
|
|
}
|
|
|
|
|
|
|
|
#poolMousedown(ev) {
|
|
|
|
let { y } = ev
|
|
|
|
let { top } = offset(ev.currentTarget)
|
|
|
|
let { scrollTop } = ROOT
|
|
|
|
let { clientHeight: h } = ev.currentTarget
|
|
|
|
let _y = top - scrollTop
|
|
|
|
|
|
|
|
y -= _y
|
|
|
|
|
|
|
|
this.#changeHue(~~((y / h) * 360))
|
|
|
|
|
|
|
|
let callback = bind(DOC, 'mousemove', ({ y }) => {
|
|
|
|
y -= _y
|
|
|
|
this.#changeHue(~~((y / h) * 360))
|
|
|
|
})
|
|
|
|
bind(DOC, 'mouseup', _ => unbind(DOC, 'mousemove', callback), EV_OPTION)
|
|
|
|
}
|
|
|
|
|
2023-11-29 11:42:01 +08:00
|
|
|
#close() {
|
2023-11-24 18:38:06 +08:00
|
|
|
if (this.#show) {
|
|
|
|
this.#show = false
|
|
|
|
this.#calc(this.value)
|
|
|
|
this.#updateView()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#submit() {
|
|
|
|
this.value = this.#value
|
|
|
|
this.#close()
|
2023-11-29 11:42:01 +08:00
|
|
|
this.$emit('input')
|
|
|
|
this.$emit('change')
|
2023-11-24 18:38:06 +08:00
|
|
|
}
|
|
|
|
|
2023-03-23 19:42:15 +08:00
|
|
|
#updateView() {
|
2023-11-29 11:42:01 +08:00
|
|
|
let hsb = this.#hsb
|
|
|
|
let rgba = this.#rgba
|
|
|
|
let sceneBg, color, alphaBg
|
|
|
|
let x, y
|
2023-03-23 19:42:15 +08:00
|
|
|
|
|
|
|
x = Math.ceil((hsb.s * 280) / 100)
|
|
|
|
y = 180 - Math.ceil((hsb.b * 180) / 100)
|
|
|
|
|
|
|
|
sceneBg = '#' + rgb2hex(hsb2rgb({ h: hsb.h, s: 100, b: 100 }))
|
|
|
|
alphaBg = '#' + rgb2hex(rgba)
|
|
|
|
|
|
|
|
if (rgba.a < 100) {
|
|
|
|
color = `rgba(${rgba.r}, ${rgba.g}, ${rgba.b}, ${rgba.a / 100})`
|
|
|
|
} else {
|
|
|
|
color = alphaBg
|
|
|
|
}
|
|
|
|
|
|
|
|
this.#sceneBg = sceneBg
|
|
|
|
this.#alphaBg = alphaBg
|
|
|
|
this.#value = color
|
|
|
|
this.#x = x
|
|
|
|
this.#y = y
|
|
|
|
this.#ht = hsb.h / 2
|
|
|
|
this.#at = rgba.a
|
|
|
|
this.$requestUpdate()
|
|
|
|
}
|
|
|
|
|
|
|
|
mounted() {
|
|
|
|
// 更新一次视图
|
2023-11-24 18:38:06 +08:00
|
|
|
this.#updateView()
|
2023-03-23 19:42:15 +08:00
|
|
|
|
|
|
|
// 点击外部区别时,还原之前的颜色值
|
2023-11-24 18:38:06 +08:00
|
|
|
this._outsideFn = outsideClick(this, ev => {
|
|
|
|
this.#close()
|
2023-03-23 19:42:15 +08:00
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2023-03-27 10:26:57 +08:00
|
|
|
unmounted() {
|
|
|
|
clearOutsideClick(this._outsideFn)
|
|
|
|
}
|
|
|
|
|
2023-03-23 19:42:15 +08:00
|
|
|
render() {
|
2023-11-24 18:38:06 +08:00
|
|
|
let styles = styleMap({
|
|
|
|
'--show': this.#show ? 'block' : 'none',
|
|
|
|
'--value': this.#value,
|
|
|
|
'--scene': this.#sceneBg,
|
|
|
|
'--x': this.#x + 'px',
|
|
|
|
'--y': this.#y + 'px',
|
|
|
|
'--ht': this.#ht + 'px',
|
|
|
|
'--at': this.#at + '%',
|
|
|
|
'--alpha': this.#alphaBg
|
|
|
|
})
|
|
|
|
|
2023-03-23 19:42:15 +08:00
|
|
|
return html`
|
2023-11-24 18:38:06 +08:00
|
|
|
<main class="container" style=${styles}>
|
2023-11-24 18:55:09 +08:00
|
|
|
<section class="preview focus alpha-bg" @click=${this.toggleColorPanel}>
|
2023-11-24 18:38:06 +08:00
|
|
|
<span tabindex=${this.disabled ? -1 : 0}></span>
|
2023-03-23 19:42:15 +08:00
|
|
|
</section>
|
2023-11-24 18:38:06 +08:00
|
|
|
|
|
|
|
<div class="color-panel">
|
2023-03-23 19:42:15 +08:00
|
|
|
<section class="dashboard">
|
2023-11-24 18:38:06 +08:00
|
|
|
<div class="scene" @mousedown.prevent=${this.#sceneMousedown}>
|
|
|
|
<i class="thumb"></i>
|
2023-03-23 19:42:15 +08:00
|
|
|
</div>
|
2023-11-24 18:38:06 +08:00
|
|
|
<div class="pool" @mousedown.prevent=${this.#poolMousedown}>
|
|
|
|
<i class="thumb"></i>
|
2023-03-23 19:42:15 +08:00
|
|
|
</div>
|
|
|
|
</section>
|
2023-11-24 18:38:06 +08:00
|
|
|
|
2023-03-23 19:42:15 +08:00
|
|
|
<section class="alpha-box alpha-bg">
|
2023-11-24 18:38:06 +08:00
|
|
|
<div class="bar"></div>
|
|
|
|
<i class="thumb"></i>
|
2023-03-23 19:42:15 +08:00
|
|
|
<input
|
|
|
|
class="alpha"
|
|
|
|
max="100"
|
|
|
|
min="0"
|
|
|
|
step="1"
|
|
|
|
type="range"
|
2023-11-24 18:38:06 +08:00
|
|
|
@input=${this.#changeAlpha}
|
2023-03-23 19:42:15 +08:00
|
|
|
/>
|
|
|
|
</section>
|
2023-11-24 18:38:06 +08:00
|
|
|
|
2023-03-23 19:42:15 +08:00
|
|
|
<section class="input-box">
|
2023-11-24 18:55:09 +08:00
|
|
|
<input class="input focus" :value=${this.#value} maxlength="25" />
|
2023-11-29 11:42:01 +08:00
|
|
|
<a class="clear" @click=${this.#close}>取消</a>
|
2023-11-24 18:55:09 +08:00
|
|
|
<a tabindex="0" class="submit focus" @click=${this.#submit}>确定</a>
|
2023-03-23 19:42:15 +08:00
|
|
|
</section>
|
|
|
|
</div>
|
2023-11-24 18:38:06 +08:00
|
|
|
</main>
|
2023-03-23 19:42:15 +08:00
|
|
|
`
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Color.reg('color')
|