import { Layer } from './layer'; import { PlaygroundConfigEntity, SCALE_WIDTH, Snapline, SnaplineConfigEntity } from './config'; import { DOMCache, domUtils } from '@gedit/utils/lib/browser'; import { entity } from '../../common'; export interface SnaplineNode extends DOMCache { } const snaplineStyle = (type: 'vertical' | 'horizontal') => ` padding: 4px; background-color: var(--g-titleBar-activeBackground); font-size: 12px; color: #fff; position: absolute; left: ${type === 'vertical' ? '4px' : '2px'}; border-radius: 2px; line-height: 1; top: ${type === 'vertical' ? '2px' : '-4px'}; transform-origin: 0 0; transform:${type === 'vertical' ? '' : 'rotate(-90deg)'} scale(0.85); `; /** * 参考线 */ export class SnaplineLayer extends Layer { @entity(PlaygroundConfigEntity) protected playgroundConfigEntity: PlaygroundConfigEntity; @entity(SnaplineConfigEntity) protected snaplineEntity: SnaplineConfigEntity; readonly node = domUtils.createDivWithClass('gedit-snapline'); readonly snapLineNodes = this.createDOMCache('gedit-snapline-node', '
'); drawLine(node: SnaplineNode, props: Snapline, noScale: boolean = false): void { const scale = noScale ? 1 : this.playgroundConfigEntity.finalScale; if (props.vertical || props.horizontal) { this.drawCrossLine(node, props); return; } const child = node.children[0] as HTMLDivElement; if (props.end!.y === props.start.y) { if (props.isMove) { child.innerHTML = `${Math.round(props.oldStart?.x || props.start.y)}`; child.style.cssText = snaplineStyle('horizontal'); } // 水平 node.setStyle({ left: props.start.x * scale, top: props.start.y * scale, backgroundColor: props.color, height: props.strokeWidth, width: (props.end!.x - props.start.x) * scale, pointerEvents: 'none', opacity: props.isMove ? '1' : '0.5' }); } else if (props.end!.x === props.start.x) { if (props.isMove) { child.innerHTML = `${Math.round(props.oldStart?.x || props.start.x)}`; child.style.cssText = snaplineStyle('vertical'); } // 垂直 node.setStyle({ left: props.start.x * scale, top: props.start.y * scale, backgroundColor: props.color, width: props.strokeWidth, height: (props.end!.y - props.start.y) * scale, pointerEvents: 'none', opacity: props.isMove ? '1' : '0.5' }); } else { // 斜线 const y = (props.end!.y - props.start.y) * scale; const x = (props.end!.x - props.start.x) * scale; node.innerHTML = ``; node.style.left = (props.start.x * scale) + 'px'; node.style.top = (props.start.y * scale) + 'px'; } } drawCrossLine(node: SnaplineNode, props: Snapline): void { const { scrollY, scrollX, width, height } = this.playgroundConfigEntity.config; const scale = this.playgroundConfigEntity.finalScale; if (props.vertical) { this.drawLine(node, { id: props.id, color: props.color, start: { x: props.start.x * scale , y: scrollY - SCALE_WIDTH, }, oldStart: props.start, end: { x: props.start.x * scale , y: scrollY + height + SCALE_WIDTH }, isMove: props.isMove, strokeWidth: props.strokeWidth }, true); } else { this.drawLine(node, { id: props.id, color: props.color, start: { x: scrollX - SCALE_WIDTH, y: props.start.y * scale }, end: { x: scrollX + width + SCALE_WIDTH, y: props.start.y * scale }, isMove: props.isMove, strokeWidth: props.strokeWidth }, true); } } drawOriginLine(nodeX: SnaplineNode, nodeY: SnaplineNode): void { const { originX, originY } = this.playgroundConfigEntity.config; this.drawCrossLine(nodeX, { id: 'horizontal_origin', color: 'red', strokeWidth: 1, horizontal: true, start: { x: originX, y: originY } }); this.drawCrossLine(nodeY, { id: 'vertical_origin', color: 'blue', strokeWidth: 1, vertical: true, start: { x: originX, y: originY } }); } draw(): void { const { originlineVisible, lines } = this.snaplineEntity.config; const nodes = this.snapLineNodes.getMore(originlineVisible ? lines.length + 2 : lines.length); // 原点线 if (originlineVisible) { this.drawOriginLine(nodes[0], nodes[1]); lines.forEach((line, i) => this.drawLine(nodes[i + 2], line)); } else { lines.forEach((line, i) => this.drawLine(nodes[i], line)); } } }