|
@@ -0,0 +1,240 @@
|
|
|
+import { Events } from "queenjs";
|
|
|
+import { reactive } from "vue";
|
|
|
+import OnMouseDown from "./mouseDown";
|
|
|
+import { ObjsContainer } from "../SelectCtrl/ObjsContainer";
|
|
|
+import { CONST, downOptions, moveOptions, rotateOptions, scaleOptions } from "./state";
|
|
|
+import { Matrix } from "../SelectCtrl/matrix";
|
|
|
+import { Project, VectorLenth } from "../SelectCtrl/objects/mathUtils";
|
|
|
+
|
|
|
+export class TransformCtrl extends Events {
|
|
|
+ state = reactive({
|
|
|
+ toolbarNames: [] as string[], //当前toolbars的名称
|
|
|
+ showScaleBridge: true,
|
|
|
+ showScaletop: true,
|
|
|
+ showScalebottom: true,
|
|
|
+
|
|
|
+ matrixInvert: 'matrix(1,0,0,1,0,0)',
|
|
|
+ relWidth: 0,
|
|
|
+ relHeight: 0,
|
|
|
+ width: 100,
|
|
|
+ height: 100,
|
|
|
+ matrix: 'matrix(1,0,0,1,0,0)',
|
|
|
+ visible: true,
|
|
|
+ baseTop: 0,
|
|
|
+ bbox: {x:0, y: 0, w: 0, h:0},
|
|
|
+ })
|
|
|
+ //所有toolbar组件
|
|
|
+ toolbars = {} as {[key :string]: (props: any)=>JSX.Element};
|
|
|
+
|
|
|
+ minBox ?:{x:number, y:number, w:number, h:number}
|
|
|
+ maxBox ?:{x:number, y:number, w:number, h:number}
|
|
|
+ baseBox = {x:0, y:0, w: 0, h: 0}
|
|
|
+
|
|
|
+ objContainer = new ObjsContainer([]);
|
|
|
+
|
|
|
+ onClickToolbar(toolName:string) {
|
|
|
+ this.emit("onClickToolbar", toolName);
|
|
|
+ }
|
|
|
+ setToolbar(toolbars: string[]) {
|
|
|
+ this.state.toolbarNames = toolbars;
|
|
|
+ }
|
|
|
+ setToolBarComps(barComps: {[key :string]: ()=>JSX.Element}) {
|
|
|
+ this.toolbars = barComps;
|
|
|
+ }
|
|
|
+
|
|
|
+ initUI(ui: HTMLElement) {
|
|
|
+
|
|
|
+ ui.addEventListener("mousedown", (e:MouseEvent)=>{
|
|
|
+ e.preventDefault();
|
|
|
+ e.stopPropagation();
|
|
|
+ OnMouseDown(this, e);
|
|
|
+ });
|
|
|
+ }
|
|
|
+
|
|
|
+ moving(e:MouseEvent) {
|
|
|
+ const objContainer = this.objContainer;
|
|
|
+ if (moveOptions._initMovePos.x == -1 && moveOptions._initMovePos.y == -1) {
|
|
|
+ moveOptions._initMovePos = { x: objContainer.parent.x, y: objContainer.parent.y };
|
|
|
+ }
|
|
|
+ objContainer.setPivot(0);
|
|
|
+ const dtx = e.clientX - moveOptions._movePreClientX;
|
|
|
+ const dty = e.clientY - moveOptions._movePreClientY;
|
|
|
+ objContainer.translate(
|
|
|
+ dtx,
|
|
|
+ dty
|
|
|
+ );
|
|
|
+ this.updateState();
|
|
|
+ this.emit("moving", dtx, dty);
|
|
|
+ }
|
|
|
+
|
|
|
+ rotate(e:MouseEvent) {
|
|
|
+
|
|
|
+ let StartX = e.clientX - this.baseBox.x;
|
|
|
+ let StartY = e.clientY - this.baseBox.y;
|
|
|
+
|
|
|
+ const objContainer = this.objContainer as ObjsContainer;
|
|
|
+
|
|
|
+ //获取当前屏幕坐标和选框中心点坐标,计算旋转值
|
|
|
+ if (!rotateOptions.rotateCenter) {
|
|
|
+ //let rect = this.objContainer.parent.getBounds(false);
|
|
|
+ let center = objContainer.setPivot(4);
|
|
|
+ rotateOptions.rotateCenter = center;
|
|
|
+
|
|
|
+ let vec = { x: StartX - center.x, y: StartY - center.y };
|
|
|
+ let angle = Math.atan2(vec.y, vec.x);
|
|
|
+ if (angle < 0) angle += 2 * Math.PI;
|
|
|
+ rotateOptions.ratatePre = angle;
|
|
|
+ rotateOptions.objinitAngleRad = objContainer.parent.rotation;
|
|
|
+ rotateOptions.rotateCmd = true;
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ let center = rotateOptions.rotateCenter;
|
|
|
+ let vec = { x: StartX - center.x, y: StartY - center.y };
|
|
|
+ let angle = Math.atan2(vec.y, vec.x);
|
|
|
+ if (angle < 0) angle += 2 * Math.PI;
|
|
|
+
|
|
|
+ let dta = rotateOptions.objinitAngleRad + angle - rotateOptions.ratatePre;
|
|
|
+ if (e.shiftKey) {
|
|
|
+ //规整到0 90 180 270
|
|
|
+ if (dta < 0) dta += 2 * Math.PI;
|
|
|
+ let Deg45 = Math.PI / 4.0;
|
|
|
+ let Deg90 = Math.PI / 2.0;
|
|
|
+ let Deg135 = Deg45 * 3;
|
|
|
+ let Deg225 = Deg45 * 5;
|
|
|
+ let Deg270 = Deg45 * 6;
|
|
|
+ let Deg315 = Deg45 * 7;
|
|
|
+ if (dta < Deg45) {
|
|
|
+ dta = 0;
|
|
|
+ } else if (dta < Deg135) {
|
|
|
+ dta = Deg90;
|
|
|
+ } else if (dta < Deg225) {
|
|
|
+ dta = Math.PI;
|
|
|
+ } else if (dta < Deg315) {
|
|
|
+ dta = Deg270;
|
|
|
+ } else {
|
|
|
+ dta = 0;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ rotateOptions.lastRad = dta;
|
|
|
+ objContainer.rotate(dta);
|
|
|
+
|
|
|
+ this.updateState();
|
|
|
+ }
|
|
|
+ scale(event:MouseEvent) {
|
|
|
+
|
|
|
+ let dirIndexs = [
|
|
|
+ "scaleBottomright",
|
|
|
+ "scaleBottomleft",
|
|
|
+ "scaleTopleft",
|
|
|
+ "scaleTopright",
|
|
|
+ ];
|
|
|
+ let dirOrth = ["scaleright", "scaleleft", "scalebottom", "scaletop"];
|
|
|
+
|
|
|
+ let StartX = event.clientX - this.baseBox.x;
|
|
|
+ let StartY = event.clientY - this.baseBox.y;
|
|
|
+ const objContainer = this.objContainer as ObjsContainer;
|
|
|
+
|
|
|
+ //获取当前屏幕坐标和选框中心点坐标,计算旋转值
|
|
|
+ if (!scaleOptions.scalePivot) {
|
|
|
+ let dir = downOptions._mouseDownFlag;
|
|
|
+ let scaleIndex = dirIndexs.indexOf(dir);
|
|
|
+ if (scaleIndex == -1) {
|
|
|
+ scaleIndex = dirOrth.indexOf(dir);
|
|
|
+ if (scaleIndex == 2) scaleIndex = 0;
|
|
|
+ }
|
|
|
+ let pivot = objContainer.setPivot(scaleIndex);
|
|
|
+
|
|
|
+ scaleOptions.scaleIndex = scaleIndex;
|
|
|
+ scaleOptions.scalePivot = pivot;
|
|
|
+
|
|
|
+ scaleOptions.mainAxisVector = { x: StartX - pivot.x, y: StartY - pivot.y };
|
|
|
+ let scale = objContainer.parent.scale;
|
|
|
+ scaleOptions.initScale = { x: scale.x, y: scale.y };
|
|
|
+ scaleOptions.initScaleWith = { w: objContainer.width, h: objContainer.height };
|
|
|
+
|
|
|
+ scaleOptions.mainAxisVectorLenth = VectorLenth(
|
|
|
+ scaleOptions.mainAxisVector.x,
|
|
|
+ scaleOptions.mainAxisVector.y
|
|
|
+ );
|
|
|
+
|
|
|
+ let ret = objContainer.getPivotXY(scaleIndex);
|
|
|
+
|
|
|
+ scaleOptions.xAxisVector = ret.x;
|
|
|
+ scaleOptions.xAxisVectorLength = VectorLenth(ret.x.x, ret.x.y);
|
|
|
+ scaleOptions.yAxisVector = ret.y;
|
|
|
+ scaleOptions.yAxisVectorLength = VectorLenth(ret.y.x, ret.y.y);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ scaleOptions.scaleCmd = true;
|
|
|
+
|
|
|
+ let center = scaleOptions.scalePivot;
|
|
|
+ let vec = { x: StartX - center.x, y: StartY - center.y };
|
|
|
+
|
|
|
+ if (event.shiftKey) {
|
|
|
+ //按住shift 自由缩放
|
|
|
+ let dtaX = Project(vec, scaleOptions.xAxisVector) / scaleOptions.xAxisVectorLength;
|
|
|
+ let dtaY = Project(vec, scaleOptions.yAxisVector) / scaleOptions.yAxisVectorLength;
|
|
|
+ scaleOptions.lastScale.x = dtaX * scaleOptions.initScale.x;
|
|
|
+ scaleOptions.lastScale.y = dtaY * scaleOptions.initScale.y;
|
|
|
+ // objContainer.scale(this.lastScale.x, this.lastScale.y);
|
|
|
+ const currW = scaleOptions.initScaleWith.w * scaleOptions.lastScale.x;
|
|
|
+ objContainer.scaleSize(currW, scaleOptions.lastScale.y * scaleOptions.initScaleWith.h);
|
|
|
+ } else {
|
|
|
+ let mainVec = scaleOptions.mainAxisVector;
|
|
|
+ let dtaScale = Project(vec, mainVec) / scaleOptions.mainAxisVectorLenth;
|
|
|
+ console.log("dtaScale=>", dtaScale);
|
|
|
+
|
|
|
+ let i = dirOrth.indexOf(downOptions._mouseDownFlag);
|
|
|
+ if (i == -1) {
|
|
|
+ scaleOptions.lastScale.x = dtaScale * scaleOptions.initScale.x;
|
|
|
+ scaleOptions.lastScale.y = dtaScale * scaleOptions.initScale.y;
|
|
|
+
|
|
|
+ if (downOptions._state ==CONST.MODE_SCALE_SCALE) {
|
|
|
+ objContainer.scale(scaleOptions.lastScale.x, scaleOptions.lastScale.y);
|
|
|
+ } else {
|
|
|
+ objContainer.scaleSize(scaleOptions.lastScale.x, scaleOptions.lastScale.y);
|
|
|
+ }
|
|
|
+ } else if (i == 0 || i == 1) {
|
|
|
+ scaleOptions.lastScale.x = dtaScale * scaleOptions.initScale.x;
|
|
|
+ // objContainer.scaleX(this.lastScale.x);
|
|
|
+ objContainer.scaleWidth(scaleOptions.lastScale.x);
|
|
|
+ } else if (i == 2 || i == 3) {
|
|
|
+ scaleOptions.lastScale.y = dtaScale * scaleOptions.initScale.y;
|
|
|
+ // objContainer.scaleY(this.lastScale.y);
|
|
|
+ objContainer.scaleHeight(scaleOptions.lastScale.y);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ this.updateState();
|
|
|
+ }
|
|
|
+
|
|
|
+ updateState() {
|
|
|
+ const selector = this.objContainer;
|
|
|
+ let obj = selector.parent;
|
|
|
+ let tmp = new Matrix();
|
|
|
+ tmp.copyFrom(obj.worldTransform);
|
|
|
+ let matrix = `matrix(${tmp.a},${tmp.b},${tmp.c},${tmp.d},${tmp.tx},${tmp.ty})`;
|
|
|
+
|
|
|
+ tmp.rotate(-tmp.getRotate());
|
|
|
+ tmp.invert();
|
|
|
+ let matrixInvert = `matrix(${tmp.a},${tmp.b},${tmp.c},${tmp.d},0,0)`;
|
|
|
+ this.state.matrix = matrix;
|
|
|
+ this.state.matrixInvert = matrixInvert;
|
|
|
+
|
|
|
+ const w = selector.rect.width, h = selector.rect.height;
|
|
|
+ this.state.width = w;
|
|
|
+ this.state.height = h;
|
|
|
+ this.state.relWidth = w * obj.scale.x;
|
|
|
+ this.state.relHeight = h * obj.scale.y;
|
|
|
+
|
|
|
+ const r = this.objContainer.getBound();
|
|
|
+
|
|
|
+ this.state.bbox.x = r.left;
|
|
|
+ this.state.bbox.y = r.top;
|
|
|
+ this.state.bbox.w = r.width;
|
|
|
+ this.state.bbox.h = r.height;
|
|
|
+
|
|
|
+ this.emit("change");
|
|
|
+ }
|
|
|
+}
|