interface EventAgent extends PointerEvent { path: Array } export interface ToolEvent { target: HTMLElement, type: string } interface Option { nodeWidth: number nodeHeight: number spaceWidth: number spaceHeight: number } const colors = ['#7396bf', '#f2711c', '#2185d0', '#21ba45', '#b5cc18', '#00b5ad', '#fbbd08', '#6435c9', '#a333c8', '#e03997', '#a5673f'] export default class Toolbar { bar: HTMLDivElement // 点击回调 callback: Function = () => {} // 拖动回调 dragenter: Function = () => {} dragend: Function = () => {} // 填充颜色回调 filled: Function = (color: string) => {} // 调节器回调 changed: Function = (color: string) => {} // 缩放百分比显示 zoomTexter: HTMLElement // 删除节点按钮 deleteNode: HTMLElement // 填充颜色按钮 fillStyle: HTMLElement // 调节器按钮 setterContainer: HTMLElement // 拖动目标类型 targetType: string = 'rect' // 当前节点类型 nodeType: string = 'rect' constructor(element: HTMLDivElement) { this.bar = element this.zoomTexter = element.querySelector('#zoomTexter') || document.createElement('li') this.deleteNode = element.querySelector('#deleteNode') || document.createElement('li') this.fillStyle = element.querySelector('#fillStyle') || document.createElement('li') this.setterContainer = element.querySelector('#setterContainer') || document.createElement('li') // 拖动开始事件 document.addEventListener('dragstart', (event: DragEvent) => { if (event.target instanceof HTMLElement) { this.targetType = event.target.dataset.type || 'rect' } }, false) // 拖动结束事件 document.addEventListener('dragend', (event: DragEvent) => { setTimeout(() => { this.dragend() }, 0) }, false) // 点击事件代理 element.onclick = (event: EventAgent) => { const path = event.path ? event.path : (event.composedPath ? event.composedPath() : []) // 通过 path 找到触发事件的 li 元素 const toolItem = path.find((item: HTMLElement) => { if (item.localName === 'li') { return item } }) if (toolItem && toolItem instanceof HTMLElement) { const type = toolItem.dataset.type || 'rect' // 打开和关闭颜色选择器, 间距调节器 if (type === 'pick-color') { if (toolItem.className.indexOf('opened') !== -1) { toolItem.classList.remove('opened') } else { toolItem.classList.add('opened') } event.stopPropagation() } // 打开间距调节器 if (type === 'setter') { toolItem.classList.add('opened') event.stopPropagation() } if (this.callback) { const enabledItem = element.querySelector('li.item-node.enabled') if (enabledItem) { enabledItem.classList.remove('enabled') toolItem.classList.add('enabled') this.nodeType = type } // 执行点击事件回调 this.callback({ target: toolItem, type: type }) } } } this.initPickColor() this.initSetter() document.addEventListener('click', () => { this.fillStyle.classList.remove('opened') this.setterContainer.classList.remove('opened') }) } initPickColor() { const pickColor: null | HTMLDivElement = this.fillStyle.querySelector('#pickColor') if (pickColor) { const fillhtml = colors.map(color => { return `` }).join('') pickColor.innerHTML = `
${fillhtml}
` pickColor.onclick = (e) => { e.stopPropagation() if (e.target instanceof HTMLElement && e.target.localName === 'span') { this.filled(e.target.dataset.color) } } } } initSetter() { const setter: null | HTMLDivElement = this.setterContainer.querySelector('#setter') if (setter) { const spaceWidth: null | HTMLInputElement = this.setterContainer.querySelector('#spaceWidth') const spaceHeight: null | HTMLInputElement = this.setterContainer.querySelector('#spaceHeight') const spaceWidthText: null | HTMLElement = this.setterContainer.querySelector('#spaceWidthText') const spaceHeightText: null | HTMLElement = this.setterContainer.querySelector('#spaceHeightText') if (spaceWidth && spaceHeight && spaceWidthText && spaceHeightText) { // 左右间距调节器发生变化时 spaceWidth.oninput = () => { spaceWidthText.textContent = spaceWidth.value this.changed({ spaceWidth: parseInt(spaceWidth.value, 10), spaceHeight: parseInt(spaceHeight.value, 10) }) } // 上下间距调节器发生变化时 spaceHeight.oninput = () => { spaceHeightText.textContent = spaceHeight.value this.changed({ spaceWidth: parseInt(spaceWidth.value, 10), spaceHeight: parseInt(spaceHeight.value, 10) }) } } } } onClick(callback: Function) { this.callback = callback } onDrag(callback: Function) { this.dragenter = callback } onDragend(callback: Function) { this.dragend = callback } onFill(callback: Function) { this.filled = callback } onChange(callback: Function) { this.changed = callback } setZoomText(text: number) { this.zoomTexter.textContent = text + '%' } enableDeleteNode() { this.deleteNode.classList.add('enabled') this.fillStyle.classList.add('enabled') } disableDeleteNode() { this.deleteNode.classList.remove('enabled') this.fillStyle.classList.remove('enabled') } static init(container: HTMLDivElement, options: Option) { //创建 Adder Box const box = document.createElement('div') box.classList.add('toolbar') // 图标库 // https://www.iconfont.cn/collections/detail?spm=a313x.7781069.1998910419.dc64b3430&cid=24011 // https://www.iconfont.cn/collections/detail?spm=a313x.7781069.1998910419.dc64b3430&cid=748 // https://www.iconfont.cn/collections/detail?spm=a313x.7781069.1998910419.dc64b3430&cid=18802 // https://www.iconfont.cn/collections/detail?spm=a313x.7781069.1998910419.dc64b3430&cid=14949 box.innerHTML = ` ` document.body.appendChild(box) box.style.marginLeft = `-${box.clientWidth / 2}px` const toolbar = new Toolbar(box) // 拖动事件 container.addEventListener('dragenter', (event: DragEvent) => { toolbar.dragenter(toolbar.targetType, event) }, false) return toolbar } }