渐变色field组件

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)

},

}))

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值