import { createDocument, getId, toHexString } from './utils/tools' import html2canvas from 'html2canvas' import { styleObj } from './utils/constant' const COLOR_ITEM_SIZE = 11 export class ColorGetPoint { private canvasContainer: HTMLDivElement | null = null // canvas容器元素 private canvas: HTMLCanvasElement | null = null // 截屏canvas private context: CanvasRenderingContext2D | null = null // 截屏canvas[context] private floatContainer: HTMLDivElement | null = null // 鼠标移动时的浮动容器元素 onChange?: (color: string) => void // 点击鼠标后的回调 color = '' // 颜色值 private elementId = '' // 元素唯一id private colorArr: { el: HTMLDivElement row: number col: number }[] = [] // 放大镜颜色数组 constructor( onChange?: (color: string) => void // 点击后回调 ) { this.onChange = onChange } /** * 初始化canvas容器 * @returns canvas容器 */ private initContainer() { const canvasContainer = createDocument( 'div', styleObj.canvasContainer, document.body ) this.canvasContainer = canvasContainer return canvasContainer } /** * 开启取色器 */ open() { this.elementId = getId() this.initContainer() html2canvas(document.body).then((canvas) => { if (canvas && this.canvasContainer) { this.initEvent(canvas) this.canvasContainer.style.display = 'block' this.canvasContainer.appendChild(canvas) this.canvas = canvas this.context = canvas.getContext('2d') this.initFloatContainer() } }) } /** * 初始化事件 * @param canvas */ private initEvent(canvas: HTMLCanvasElement) { canvas.addEventListener('mousemove', this.canvasMouseMove) canvas.addEventListener('mousedown', this.canvasMouseDown) window.addEventListener('keydown', this.onKeyDown) } /** * canvas移动事件 * @param e */ private canvasMouseMove = (e: MouseEvent) => { if (this.context) { const x = e.pageX * window.devicePixelRatio const y = e.pageY * window.devicePixelRatio // 获取放大镜所需区域颜色 const colors = this.getColors(x, y) if (this.floatContainer && colors) { // 根据坐标改变放大镜位置 this.floatContainer.style.transform = `translate(${e.pageX - 82.5}px, ${ e.pageY - 82.5 }px )` if (this.floatContainer.style.visibility === 'hidden') { this.floatContainer.style.visibility = 'visible' } const textEl = document.getElementById(`${this.elementId}text`) // 遍历每个颜色块,修改颜色 for ( let i = 0, size = COLOR_ITEM_SIZE * COLOR_ITEM_SIZE; i < size; i++ ) { const { el, row, col } = this.colorArr[i] const [r, g, b, a] = colors[i] // toHexString rgba转16进制 const hexStr = toHexString({ r, g, b, a: a / 255 }) // 最中间的颜色保存起来 if (row === 6 && col === 6 && textEl) { textEl.textContent = hexStr textEl.style.color = hexStr this.color = hexStr } el.style.backgroundColor = hexStr } } } } /** * 监听鼠标按下 */ private canvasMouseDown = () => { this?.onChange?.(this.color) this.destroy() } /** * 获取放大镜所需区域颜色 * @param x * @param y * @returns */ private getColors(x: number, y: number) { if (this.context) { const { data } = this.context.getImageData( x - 5, y - 5, COLOR_ITEM_SIZE, COLOR_ITEM_SIZE ) const colors = [] for (let i = 0; i < data.length; i += 4) { colors.push([data[i], data[i + 1], data[i + 2], data[i + 3]]) } return colors } } /** * esc按键监听 * @param e */ private onKeyDown = (e: KeyboardEvent) => { if (e.code === 'Escape') { this.destroy() } } /** * 初始化浮动元素容器 */ private initFloatContainer() { if (this.canvasContainer) { // 创建浮动元素容器 const floatContainer = createDocument( 'div', styleObj.floatContainer, this.canvasContainer ) // 创建放大镜的小颜色块 const fragment = document.createDocumentFragment() for (let i = 1; i <= COLOR_ITEM_SIZE * COLOR_ITEM_SIZE; i++) { const row = Math.ceil(i / COLOR_ITEM_SIZE) const col = i - (row - 1) * COLOR_ITEM_SIZE const style: Record = { ...styleObj.colorItem } if (row === 6 && col === 6) { style.borderColor = '#000000' } const itemEl = createDocument('div', style, fragment) itemEl.setAttribute('id', `${this.elementId}${i}`) this.colorArr.push({ el: itemEl, row, col }) } floatContainer.appendChild(fragment) const textEl = createDocument('div', styleObj.text, floatContainer) textEl.setAttribute('id', `${this.elementId}text`) floatContainer.addEventListener('mousemove', this.canvasMouseMove) floatContainer.addEventListener('mousedown', this.canvasMouseDown) this.floatContainer = floatContainer } } /** * 结束销毁 */ destroy() { if (this.canvas) { this.canvas.removeEventListener('mousemove', this.canvasMouseMove) this.canvas.removeEventListener('mousedown', this.canvasMouseDown) } if (this.floatContainer) { this.floatContainer.removeEventListener('mousemove', this.canvasMouseMove) this.floatContainer.removeEventListener('mousedown', this.canvasMouseDown) } if (this.canvasContainer) { document.body.removeChild(this.canvasContainer) } window.removeEventListener('keydown', this.onKeyDown) } }