import { ModuleControl } from "queenjs"; import { reactive } from "vue"; import { EditorModule } from "../../module"; import { DesignComp } from "../../objects/DesignTemp/DesignComp"; import * as transforms from "./transforms"; type TransHandle = (this: TransferCtrl, e: MouseEvent) => void; export type TransCreateFn = (...args: any[]) => { mousedown?: TransHandle; mousemove: TransHandle; mouseup: TransHandle; }; export class TransferCtrl extends ModuleControl { compEl!: HTMLElement; pageEl!: HTMLElement; currComp!: DesignComp; currTransfer!: ReturnType; currObserver?: MutationObserver; transforms = transforms; transEvent = { startX: 0, startY: 0, offsetX: 0, offsetY: 0, width: 0, height: 0, }; transferStyle = reactive({ top: "", left: "", width: "", height: "", transform: { scale: 1, rotate: "0deg", translateX: "-50%", translateY: "-50%", }, }); originPiont = { x: 0, y: 0, }; init(pageEl: HTMLElement) { this.currComp = this.module.store.currComp; this.compEl = this.currComp.$el; this.pageEl = pageEl; this.observe(); } mousedown(e: MouseEvent, type: keyof typeof transforms, currComp?: any) { if (!currComp) { currComp = this.store.currComp; } this.currComp = currComp; this.compEl = currComp.$el; this.transEvent = { startX: e.clientX, startY: e.clientY, offsetX: 0, offsetY: 0, width: currComp.layout.size?.[0] || currComp.$el.clientWidth * 2, height: currComp.layout.size?.[1] || currComp.$el.clientHeight * 2, }; this.currTransfer = this.transforms[type](); document.addEventListener("mousemove", this.mousemove); document.addEventListener("mouseup", this.mouseup); this.currTransfer.mousedown?.call(this, e); } private mousemove = (e: MouseEvent) => { const { transEvent } = this; transEvent.offsetX = e.clientX - transEvent.startX; transEvent.offsetY = e.clientY - transEvent.startY; this.currTransfer.mousemove.call(this, e); }; private mouseup = (e: MouseEvent) => { document.removeEventListener("mousemove", this.mousemove); document.removeEventListener("mouseup", this.mouseup); this.currTransfer.mouseup.call(this, e); }; observe() { if (this.currObserver) { this.currObserver.disconnect(); } this.initStyle(); this.currObserver = new MutationObserver((mutations) => { mutations.forEach((mutation) => { if ( mutation.type === "childList" || (mutation.type === "attributes" && mutation.attributeName === "style") ) { this.initStyle(); } }); }); this.currObserver.observe(this.compEl, { attributes: true, childList: true, subtree: true, characterData: true, }); } initStyle() { if (!this.compEl) return; const rect = this.compEl.getBoundingClientRect(); const pageRect = this.pageEl.getBoundingClientRect(); const transform = getTransform(this.compEl); const width = this.compEl.clientWidth * transform.scale; const height = this.compEl.clientHeight * transform.scale; this.transferStyle.width = width + "px"; this.transferStyle.height = height + "px"; this.transferStyle.top = rect.top + rect.height / 2 - pageRect.top + "px"; this.transferStyle.left = rect.left + rect.width / 2 - pageRect.left + "px"; if (!this.transferStyle.transform) { this.transferStyle.transform = { scale: 1, rotate: "0deg", translateX: "-50%", translateY: "-50%", }; } this.transferStyle.transform.scale = transform.scale; this.transferStyle.transform.rotate = transform.rotate; this.transferStyle.transform.translateY = "-" + height / 2 + "px"; this.originPiont.x = rect.left + rect.width / 2; this.originPiont.y = rect.top + rect.height / 2; } resetStyle() { Object.keys(this.transferStyle).forEach((key) => { (this.transferStyle as any)[key] = ""; }); } destroy() { this.currObserver?.disconnect(); this.resetStyle(); } } export function getTransform(el: HTMLElement) { const st = getComputedStyle(el, null); const tr = st.getPropertyValue("-webkit-transform") || st.getPropertyValue("-moz-transform") || st.getPropertyValue("-ms-transform") || st.getPropertyValue("-o-transform") || st.getPropertyValue("transform") || "FAIL"; // console.error("Matrix: " + tr); if (tr == "none") return { rotate: "0deg", scale: 1, }; // rotation matrix - http://en.wikipedia.org/wiki/Rotation_matrix const values = tr.split("(")[1].split(")")[0].split(","); // console.error("values: ", values); const a: any = values[0]; const b: any = values[1]; const angle = Math.round(Math.atan2(b, a) * (180 / Math.PI)); const scale = Math.sqrt(a * a + b * b); return { rotate: `${angle}deg`, scale, }; }