export const GradientColorField = observer(({label, value, defaultValue, gradientColor, gradientColorType = 'linear', onChange = () => {}, className, readOnly}) => {
const [rect, setRect] = useState({})
const [circle, setCircle] = useState({})
const [activeKey, setActiveKey] = useState(null)
const [canShowPicker, setCanShowPicker] = useState(false)
const [isClick, setIsClick] = useState(false)
const rectRef = useRef()
const colorPickerBox = useRef()
const {gradientColorList} = value
const getGradientColorListInit = () => {
const listCopy = JSON.parse(JSON.stringify(gradientColorList))
listCopy.map((item, index) => {
if (index === 0 && !item.key) {
item.key = 'g0'
item.position = 0
item.stop = 50
} else if (index === listCopy.length - 1 && !item.key) {
item.key = 'g1'
item.position = 1
item.stop = 50
}
})
return listCopy
}
const gradientColorListInit = getGradientColorListInit()
// 获取矩形空间的位置
useEffect(() => {
const boundingClientRect = {
x: rectRef.current.getBoundingClientRect().x,
y: rectRef.current.getBoundingClientRect().y,
width: rectRef.current.getBoundingClientRect().width,
}
// if (JSON.stringify(rect) !== JSON.stringify(boundingClientRect)) {
setRect(boundingClientRect)
// }
}, [])
// 鼠标拖动圆点
useEffect(() => {
const {key, x, y} = circle
const circleNode = document.querySelector(`.${key}`)
if (circleNode) {
// 用于保存小的div拖拽前的坐标
circleNode.startX = x - circleNode.offsetLeft
circleNode.startY = y
// 鼠标的移动事件
document.onmousemove = e => {
circleNode.style.left = `${e.clientX - circleNode.startX}px`
circleNode.style.top = `${e.clientY - circleNode.startY}px`
// 对于大的DIV四个边界的判断
if (e.clientX - circleNode.startX <= -7) {
circleNode.style.left = `${-7}px`
}
if (e.clientY - circleNode.startY <= 0) {
circleNode.style.top = `${-7}px`
}
if (e.clientX - circleNode.startX >= rect.width - 7) {
circleNode.style.left = `${rect.width - 7}px`
}
if (e.clientY - circleNode.startY >= 0) {
circleNode.style.top = `${-7}px`
}
if (e.clientX >= rect.x && e.clientX <= rect.x + rect.width) {
// 更新颜色位置
const position = (e.clientX - rect.x) / rect.width
const copyList = JSON.parse(JSON.stringify(gradientColorListInit))
copyList.find(item => item.key === key).position = position
onChange({gradientColorType, gradientColorList: copyList})
}
}
// 鼠标的抬起事件,终止拖动
document.onmouseup = e => {
// 位置移动后点击事件取消
if (e.clientX !== x) {
setIsClick(false)
}
document.onmousemove = null
document.onmouseup = null
// log.info('mouseup')
}
}
}, [circle])
useEffect(() => {
if (canShowPicker) {
// 展示的时候,修改colorPicker的位置,下面如果超出innerHeight, 那就展示在上边
const colorPickerBoxDom = colorPickerBox.current
const {top, height} = colorPickerBoxDom.getBoundingClientRect()
const {innerHeight} = window
if ((top + height) > innerHeight) {
colorPickerBoxDom.style.top = 'auto'
colorPickerBoxDom.style.bottom = '30px' // 28 +2 展示在上边时,行高 + 2px偏差
} else {
colorPickerBoxDom.style.top = '30px'
}
}
}, [canShowPicker])
const rgba2objMap = key => {
const rgb = gradientColorListInit.find(o => o.key === key) ? gradientColorListInit.find(o => o.key === key).color : 'rgba(0, 119, 255, 1)'
const color = rgb.replace('rgba(', '').replace(')', '').split(',')
return {
r: color[0],
g: color[1],
b: color[2],
a: color[3],
}
}
const changeColorMap = (key, rgba) => {
const copyList = JSON.parse(JSON.stringify(gradientColorListInit))
copyList.find(o => o.key === key).color = rgba
return {gradientColorType, gradientColorList: copyList}
}
return <Field
label={label}
className={className}
>
<div ref={rectRef} className="fbh fbac fbjc w100p" style={{background: gradientColor}}
onDoubleClick={e => {
// 阻止事件冒泡
e.stopPropagation()
e.preventDefault()
const position = (e.clientX - rect.x) / rect.width
const copyList = JSON.parse(JSON.stringify(gradientColorListInit))
if (copyList.findIndex(o => o.position === position) === -1) {
copyList.push({
key: `g${new Date().getTime()}`,
position,
color: 'rgba(0, 119, 255, 1)',
stop: 50,
gradientType: 'linear',
})
onChange({gradientColorType, gradientColorList: copyList})
}
// log.info('doubleClick')
}}
onClick={e => {
// 阻止事件冒泡
e.stopPropagation()
setActiveKey(null)
setCanShowPicker(false)
}}
>
<div
className={c('pr w100p', s.baseLine)}
>
{gradientColorListInit.map((item, index) => {
const {key, position, color, stop} = item
// TODO 解决onClick与onMouseDown, onMouseUp的冲突
return Children.toArray(
<div className={c(key, s.circle, {[s.activeCircle]: activeKey === key})}
tabIndex={-1}
style={{background: color, left: rect.width ? rect.width * position - 7 : 0}}
draggable={false}
onClick={e => {
// 阻止事件冒泡
e.stopPropagation()
if (isClick) {
// 聚焦
e.target.focus()
setActiveKey(key)
setCanShowPicker(true)
}
// log.info('click')
// 取消鼠标移动事件
document.onmousemove = null
}}
onKeyDown={e => {
// 删除按键
if (e.key === 'Backspace' && gradientColorListInit.length > 2) {
onChange({gradientColorType, gradientColorList: gradientColorListInit.filter(o => o.key !== key)})
setCanShowPicker(false)
}
}}
onMouseDown={e => {
// log.info('mousedown')
// 阻止事件冒泡
e.stopPropagation()
setCircle({key, x: e.clientX, y: e.clientY})
setIsClick(true)
}}
/>
)
})}
</div>
</div>
{canShowPicker && <div ref={colorPickerBox} className={s.pickerBox}>
{/* 用一个fixed的div 展示在colorPicker下面,点击这个div时,触发关闭 */}
<div className={s.cover} onClick={() => {
setActiveKey(null)
setCanShowPicker(false)
}} />
<SketchPicker
color={rgba2objMap(activeKey)}
onChange={color => {
const rgba = `rgba(${color.rgb.r},${color.rgb.g},${color.rgb.b},${color.rgb.a})`
onChange(changeColorMap(activeKey, rgba))
}} />
</div>}
</Field>
})
export const MGradientColorField = types.model('MGradientColorField', {
section: types.optional(types.string, ''),
type: types.enumeration(['gradientColor']),
label: types.optional(types.string, ''),
value: types.frozen(),
defaultValue: types.optional(types.frozen(), {gradientColorType: 'linear', gradientColorList: [{color: 'rgba(0, 119, 255, 1)'}, {color: 'rgba(80, 227, 194, 1)'}]}),
readOnly: types.optional(types.boolean, false),
when: types.frozen(),
useReaction: types.optional(types.boolean, false),
}).views(self => (commonFieldModelViews(self))).views(self => ({
get gradientColor() {
const {gradientColorType, gradientColorList} = self.value
const gradientColorOption = gradientColorType === 'linear' ? '90deg,' : ''
const copyList = JSON.parse(JSON.stringify(gradientColorList))
let colorList = ''
if (gradientColorList.length === 2 && !gradientColorList[0].key) {
return `${gradientColorType}-gradient(${gradientColorOption} ${gradientColorList[0].color} 0%, ${gradientColorList[1].color} 100%)`
}
copyList.sort((a, b) => a.position - b.position)
copyList.forEach((item, index) => {
colorList += `${item.color} ${item.position * 100}%${index === copyList.length - 1 ? '' : ','}`
})
return `${gradientColorType}-gradient(${gradientColorOption} ${colorList})`
},
})).actions(commonAction([
'set',
])).actions(self => ({
afterCreate() {
if (!isDef(self.value)) {
self.value = self.defaultValue
}
onSnapshot(self, () => {
getParent(self).update()
})
},
setValue(value) {
self.value = value
},
clearValue() {
self.value = ''
},
// !所有field的取值都应该使用getValue方法,整合了when的逻辑
getValue() {
// pro field2
if (self.supportProcessor2 && self.hasSaveCode) {
return self.processorFunction
}
// 只要是启用状态,就返回value值
return self.whenIsSatisfied
? (isDef(self.value) ? self.value : self.defaultValue)
: undefined
},
// 开启processor后的操作
operateProcessor(operate) {
processorAction(self, operate)
},
}))