import { CanvasSmbl } from '../infrastructure/canvas-smbl.js'; import { pointInCanvas } from '../infrastructure/move-scale-applay.js'; import { listen } from '../infrastructure/util.js'; import { tipShow } from './ui.js'; export class ShapeMenu extends HTMLElement { connectedCallback() { const shadow = this.attachShadow({ mode: 'closed' }); shadow.innerHTML = `
`; const menu = shadow.getElementById('menu'); menu.querySelectorAll('[data-cmd="shapeAdd"]').forEach(el => listen(el, 'pointerdown', this)); listen(menu, 'pointerleave', this); listen(menu, 'pointerup', this); listen(menu, 'pointermove', this); }; /** @param {CanvasElement} canvas */ init(canvas) { /** @private */ this._canvas = canvas; } /** @param {PointerEvent & { currentTarget: Element }} evt */ handleEvent(evt) { switch (evt.type) { case 'pointermove': if (!this._isNativePointerleaveTriggered) { // emulate pointerleave for mobile const pointElem = document.elementFromPoint(evt.clientX, evt.clientY); if (pointElem === this._pointElem) { return; } // pointerleave if (this._parentElem === this._pointElem) { // TODO: check mobile this._canvas.ownerSVGElement.setPointerCapture(evt.pointerId); } /** * @type {Element} * @private */ this._pointElem = pointElem; } break; case 'pointerleave': this._isNativePointerleaveTriggered = true; if (this._pressedShapeTemplKey != null) { // when shape drag out from menu panel this._shapeCreate(evt); } this._clean(); break; case 'pointerdown': this._pressedShapeTemplKey = parseInt(evt.currentTarget.getAttribute('data-cmd-arg')); // for emulate pointerleave this._parentElem = document.elementFromPoint(evt.clientX, evt.clientY); this._pointElem = this._parentElem; this._isNativePointerleaveTriggered = null; break; case 'pointerup': this._clean(); break; } } /** * @param {PointerEvent} evt * @private */ _shapeCreate(evt) { tipShow(false); if (this._pressedShapeTemplKey == null) return; const svg = this._canvas.ownerSVGElement; const pt = svg.createSVGPoint(); pt.x = evt.clientX; pt.y = evt.clientY; const loc = pt.matrixTransform(this._canvas.getScreenCTM().inverse()); const x = loc.x, y = loc.y; let shapeData; if (this._pressedShapeTemplKey === 0) { shapeData = { s: { data: { dir: 'right', position: { x: x - 24, y } } }, e: { data: { dir: 'right', position: { x: x + 24, y } } } }; } else { shapeData = { type: this._pressedShapeTemplKey, position: { x, y }, title: 'Title' }; } const shapeEl = this._canvas[CanvasSmbl].shapeMap[this._pressedShapeTemplKey].create(shapeData); this._canvas.append(shapeEl); // Для стрелки и других форм диспатчим pointerdown shapeEl.dispatchEvent(new PointerEvent('pointerdown', evt)); // transform ставим только для фигур, которые не path if (this._pressedShapeTemplKey !== 0) { shapeEl.setAttribute('transform', `translate(${x},${y})`); } } /** @private */ _clean() { this._pressedShapeTemplKey = null; this._parentElem = null; this._pointElem = null; } } customElements.define('ap-menu-shape', ShapeMenu); /** @typedef { import('../shapes/shape-type-map.js').ShapeType } ShapeType */ /** @typedef { import('../infrastructure/canvas-smbl.js').CanvasElement } CanvasElement */