112 lines
3.4 KiB
JavaScript
112 lines
3.4 KiB
JavaScript
import { TpFlowNode } from './tp-flow-node.js';
|
|
|
|
export const panning = function(superClass) {
|
|
return class extends superClass {
|
|
static get properties() {
|
|
return {
|
|
isDragging: { type: Boolean },
|
|
currentX: { type: Number },
|
|
currentY: { type: Number },
|
|
initialX: { type: Number },
|
|
initialY: { type: Number },
|
|
xOffset: { type: Number },
|
|
yOffset: { type: Number },
|
|
highestZIndex: { type: Number }
|
|
};
|
|
}
|
|
|
|
constructor() {
|
|
super();
|
|
this.isDragging = false;
|
|
this.currentX = 0;
|
|
this.currentY = 0;
|
|
this.initialX = 0;
|
|
this.initialY = 0;
|
|
this.xOffset = 0;
|
|
this.yOffset = 0;
|
|
this.targetElement = null;
|
|
this.highestZIndex = 1;
|
|
}
|
|
|
|
firstUpdated() {
|
|
this.canvas = this.shadowRoot.querySelector('.canvas');
|
|
this.addEventListener('mousedown', this._startDrag.bind(this));
|
|
document.addEventListener('mousemove', this._drag.bind(this));
|
|
document.addEventListener('mouseup', this._endDrag.bind(this));
|
|
super.firstUpdated();
|
|
}
|
|
|
|
_getTopNodeAtPoint(x, y) {
|
|
const nodes = this.shadowRoot.elementsFromPoint(x, y)
|
|
.filter(el => el instanceof TpFlowNode)
|
|
.sort((a, b) => {
|
|
const aZ = parseInt(getComputedStyle(a).zIndex) || 0;
|
|
const bZ = parseInt(getComputedStyle(b).zIndex) || 0;
|
|
return bZ - aZ;
|
|
});
|
|
|
|
return nodes[0] || null;
|
|
}
|
|
|
|
_bringToFront(element) {
|
|
if (!(element instanceof TpFlowNode)) return;
|
|
|
|
this.highestZIndex++;
|
|
element.style.zIndex = this.highestZIndex;
|
|
}
|
|
|
|
_startDrag(e) {
|
|
const topNode = this._getTopNodeAtPoint(e.clientX, e.clientY);
|
|
|
|
if (topNode) {
|
|
this.targetElement = topNode;
|
|
this._bringToFront(topNode);
|
|
} else {
|
|
this.targetElement = this.canvas;
|
|
}
|
|
|
|
if (this.targetElement) {
|
|
this.isDragging = true;
|
|
|
|
const transform = window.getComputedStyle(this.targetElement).transform;
|
|
const matrix = new DOMMatrix(transform);
|
|
this.xOffset = matrix.m41;
|
|
this.yOffset = matrix.m42;
|
|
|
|
if (this.targetElement === this.canvas) {
|
|
this.initialX = e.clientX - this.xOffset;
|
|
this.initialY = e.clientY - this.yOffset;
|
|
} else {
|
|
// For nodes, compensate for scale in initial position too
|
|
this.initialX = e.clientX - (this.xOffset * this.scale);
|
|
this.initialY = e.clientY - (this.yOffset * this.scale);
|
|
}
|
|
}
|
|
}
|
|
|
|
_drag(e) {
|
|
if (this.isDragging && this.targetElement) {
|
|
e.preventDefault();
|
|
|
|
if (this.targetElement === this.canvas) {
|
|
// For canvas panning, no scale compensation needed
|
|
this.currentX = e.clientX - this.initialX;
|
|
this.currentY = e.clientY - this.initialY;
|
|
this.targetElement.style.transform =
|
|
`translate(${this.currentX}px, ${this.currentY}px) scale(${this.scale})`;
|
|
} else {
|
|
// For nodes, compensate for canvas scale
|
|
this.currentX = (e.clientX - this.initialX) / this.scale;
|
|
this.currentY = (e.clientY - this.initialY) / this.scale;
|
|
this.targetElement.style.transform =
|
|
`translate(${this.currentX}px, ${this.currentY}px)`;
|
|
}
|
|
}
|
|
}
|
|
|
|
_endDrag() {
|
|
this.isDragging = false;
|
|
this.targetElement = null;
|
|
}
|
|
};
|
|
}; |