import { Layer } from './layer'; import { EditorState, EditorStateConfigEntity, PlaygroundConfigEntity, SnaplineConfigEntity } from './config'; import { able, ables, entity, Entity, TransformData } from '../../common'; import { DOMCache, domUtils } from '@gedit/utils/lib/browser'; import { Selectable, SelectState } from '../able/selectable'; import { Align, AlignInfo, AlignType } from '../utils/align'; import { Rectangle } from '@gedit/math'; import { Adsorber } from '../utils/adsorber'; import { Adsorbable, Dragable, Resizable, Rotatable } from '../able'; /** * 对齐线相关绘制 */ export class AlignLayer extends Layer { @entity(PlaygroundConfigEntity) protected playgroundConfigEntity: PlaygroundConfigEntity; @entity(EditorStateConfigEntity) protected editorStateConfig: EditorStateConfigEntity; @able(Selectable) protected selectableNodes: Entity[]; @entity(SnaplineConfigEntity) protected snaplineEntity: SnaplineConfigEntity; @ables([Selectable], [Dragable, Resizable, Rotatable]) protected movingNodes: Entity[]; @ables([Adsorbable]) protected adsorbableNodes: Entity[]; readonly node = domUtils.createDivWithClass('gedit-alignment'); readonly lineNodes = this.createDOMCache('gedit-align-line'); drawLine(node: DOMCache, info: AlignInfo): void { const isHorizantal = Adsorber.isHorizantal(info.direction); const scale = this.playgroundConfigEntity.finalScale; if (isHorizantal) { // 水平 node.setStyle({ left: info.startPos.x * scale, top: info.startPos.y * scale - 1, width: (info.endPos.x - info.startPos.x) * scale, height: 0, }); } else { // 垂直 node.setStyle({ left: info.startPos.x * scale - 1, top: (info.startPos.y) * scale, height: (info.endPos.y - info.startPos.y) * scale, width: 0, }); } if (info.type === AlignType.LINE_BETWEEN) { node.className = `gedit-align-line gedit-align-line-between ${isHorizantal ? 'horizantal' : 'vertical'}`; node.innerHTML = `
${Math.round(Math.abs(isHorizantal ? info.startPos.x - info.endPos.x : info.startPos.y - info.endPos.y))}
`; } else { node.className = 'gedit-align-line'; node.innerHTML = ''; } } draw(): void { // 获取是否按下 Alt 键 const currentEditorState = this.editorStateConfig.getCurrentState(); const showAltAlignLine = currentEditorState && currentEditorState === EditorState.SHOW_SCENE_RANGE_RULER; if (this.movingNodes.length === 0 && !showAltAlignLine) { this.lineNodes.clear(); return; } const selectedNodes = this.selectableNodes.filter(node => node.getData(SelectState)!.selected); const adsorbableNodes = this.adsorbableNodes.filter(node => !selectedNodes.includes(node) && !TransformData.isParentOrChildrenTransform(selectedNodes, node)); const pageBounds = this.config.getPageBounds(); const nodes: Rectangle[] = selectedNodes.map(node => node.getData(TransformData)!.bounds); const selectorBoxRect = Rectangle.enlarge(nodes); let infos: AlignInfo[] = []; // 按下 alt 键时,显示边距线 if (showAltAlignLine) { // TODO 后续考虑父级节点的边距线, 目前只处理对 page 的边距线; const hoverNode = this.adsorbableNodes.find(c => c.getData(SelectState)?.hovered && !selectedNodes.some(d => d === c)); const hoverBounds = hoverNode?.getData(TransformData)?.bounds; infos = Align.calculateAll(selectorBoxRect, hoverBounds || pageBounds!); } else { infos = Align.calculate( selectorBoxRect, adsorbableNodes.map(n => n.getData(TransformData)!.bounds).concat(pageBounds ? [pageBounds] : []), this.snaplineEntity.getAdsoberLines(), ); } this.lineNodes.getMore(infos.length).forEach((n, i) => this.drawLine(n, infos[i])); } }