Browse Source

SGraphItem支持缩放与旋转操作。

sybotan 5 years ago
parent
commit
b23ce512d5

+ 24 - 1
saga-web-base/src/SMouseEvent.ts

@@ -19,12 +19,18 @@ export class SMouseEvent {
     clientX: number;
     /** 客户端Y坐标 */
     clientY: number;
+    /** X轴偏移量 */
+    offsetX: number;
+    /** Y轴偏移量 */
+    offsetY: number;
     /** 是否按下alt键 */
     altKey: boolean;
     /** 是否按下ctrl键 */
     ctrlKey: boolean;
     /** 鼠标按键 */
     buttons: number;
+    /** 变换矩阵 */
+    matrix = new DOMMatrix();
 
     /**
      * 构造函数
@@ -34,17 +40,34 @@ export class SMouseEvent {
     constructor(event: MouseEvent | SMouseEvent) {
         // let bbox = (this.type = event.type); //event.srcElement.getBoundingClientRect()
         this.type = event.type;
-
         this.screenX = event.screenX;
         this.screenY = event.screenY;
         this.clientX = event.clientX;
         this.clientY = event.clientY;
+        this.offsetX = event.offsetX;
+        this.offsetY = event.offsetY;
         this.altKey = event.altKey;
         this.ctrlKey = event.ctrlKey;
         this.buttons = event.buttons;
         if (event instanceof SMouseEvent) {
             this.x = event.x;
             this.y = event.y;
+            this.matrix.m11 = event.matrix.m11;
+            this.matrix.m12 = event.matrix.m12;
+            this.matrix.m13 = event.matrix.m13;
+            this.matrix.m14 = event.matrix.m14;
+            this.matrix.m21 = event.matrix.m21;
+            this.matrix.m22 = event.matrix.m22;
+            this.matrix.m23 = event.matrix.m23;
+            this.matrix.m24 = event.matrix.m24;
+            this.matrix.m31 = event.matrix.m31;
+            this.matrix.m32 = event.matrix.m32;
+            this.matrix.m33 = event.matrix.m33;
+            this.matrix.m34 = event.matrix.m34;
+            this.matrix.m41 = event.matrix.m41;
+            this.matrix.m42 = event.matrix.m42;
+            this.matrix.m43 = event.matrix.m43;
+            this.matrix.m44 = event.matrix.m44;
         } else {
             this.x = event.offsetX; // TODO: PLX  - bbox.left;
             this.y = event.offsetY; // TODO: PLX  - bbox.top;

+ 9 - 9
saga-web-draw/__tests__/types/SPoint.test.ts

@@ -1,33 +1,33 @@
 import { SPoint } from "../../src";
 
 test("构造函数", () => {
-    expect(JSON.stringify(new SPoint())).toBe('{"x":0,"y":0}');
-    expect(JSON.stringify(new SPoint(10, 10))).toBe('{"x":10,"y":10}');
+    expect(new SPoint().toJson()).toBe("{\"x\":0,\"y\":0}");
+    expect(new SPoint(10, 10).toJson()).toBe("{\"x\":10,\"y\":10}");
 });
 
 test("属性修改", () => {
     const p = new SPoint();
-    expect(JSON.stringify(p)).toBe('{"x":0,"y":0}');
+    expect(p.toJson()).toBe("{\"x\":0,\"y\":0}");
 
     p.y = 10;
-    expect(JSON.stringify(p)).toBe('{"x":0,"y":10}');
+    expect(p.toJson()).toBe("{\"x\":0,\"y\":10}");
     p.x = -10;
-    expect(JSON.stringify(p)).toBe('{"x":-10,"y":10}');
+    expect(p.toJson()).toBe("{\"x\":-10,\"y\":10}");
 
     p.setPoint(-100, -30);
-    expect(JSON.stringify(p)).toBe('{"x":-100,"y":-30}');
+    expect(p.toJson()).toBe("{\"x\":-100,\"y\":-30}");
 
     p.setPoint(new SPoint(-5, -12));
-    expect(JSON.stringify(p)).toBe('{"x":-5,"y":-12}');
+    expect(p.toJson()).toBe("{\"x\":-5,\"y\":-12}");
 });
 
 test("setPoint()", () => {
     const p = new SPoint();
     p.setPoint(-100, -30);
-    expect(JSON.stringify(p)).toBe('{"x":-100,"y":-30}');
+    expect(p.toJson()).toBe("{\"x\":-100,\"y\":-30}");
 
     p.setPoint(new SPoint(-5, -12));
-    expect(JSON.stringify(p)).toBe('{"x":-5,"y":-12}');
+    expect(p.toJson()).toBe("{\"x\":-5,\"y\":-12}");
 });
 
 test("manhattanLength()", () => {

+ 1 - 1
saga-web-draw/src/engines/SPaintEngine.ts

@@ -67,7 +67,7 @@ export abstract class SPaintEngine {
      * @param   angle   旋转角度(单位弧度)
      */
     rotate(angle: number): void {
-        this.state.matrix.rotateSelf(0, 0, (angle * 180) / Math.PI);
+        this.state.matrix.rotateSelf(0, 0, angle);
     } // Function rotate()
 
     /**

+ 65 - 21
saga-web-graph/src/SGraphItem.ts

@@ -91,8 +91,10 @@ export class SGraphItem extends SObject {
         this.pos.y = v;
         this.update();
     } // Set y
+
     /** 缩放比例 */
     scale: number = 1;
+    rolate: number = 0;
 
     /** 是否可见 */
     _visible: boolean = true;
@@ -170,6 +172,8 @@ export class SGraphItem extends SObject {
             painter.save();
             // item位移到指定位置绘制
             painter.translate(item.x, item.y);
+            painter.scale(item.scale, item.scale);
+            painter.rotate(item.rolate);
 
             // 如果不进行变形处理,则取消painter的变型操作
             if (!item.isTransform) {
@@ -252,7 +256,7 @@ export class SGraphItem extends SObject {
      * @return  boolean
      */
     contains(x: number, y: number): boolean {
-        return this.boundingRect().contains(x - this.x, y - this.y);
+        return this.boundingRect().contains(x, y);
     } // Function contains()
 
     /**
@@ -279,15 +283,16 @@ export class SGraphItem extends SObject {
      * @return  在item中的坐标
      */
     mapFromScene(x: number, y: number): SPoint {
+        const m = new DOMMatrix();
         let list = this.itemPath();
-        let x0 = x;
-        let y0 = y;
         for (let item of list) {
-            x0 = (x0 - item.x) / item.scale;
-            y0 = (y0 - item.y) / item.scale;
+            m.translateSelf(item.x, item.y);
+            m.scaleSelf(item.scale, item.scale);
+            m.rotateSelf(item.rolate);
         }
 
-        return new SPoint(x0, y0);
+        const mp = new DOMPoint(x, y).matrixTransform(m.inverse());
+        return new SPoint(mp.x, mp.y);
     } // Function mapFromScene()
 
     /**
@@ -303,10 +308,16 @@ export class SGraphItem extends SObject {
             return new SPoint(x, y);
         }
 
-        return this.parent.mapToScene(
-            x * this.scale + this.x,
-            y * this.scale + this.y
-        );
+        const m = new DOMMatrix();
+        let list = this.itemPath();
+        for (let item of list) {
+            m.translateSelf(item.x, item.y);
+            m.scaleSelf(item.scale, item.scale);
+            m.rotateSelf(item.rolate);
+        }
+
+        const mp = new DOMPoint(x, y).matrixTransform(m);
+        return new SPoint(mp.x, mp.y);
     } // Function mapToScene()
 
     // =================================================================================================================
@@ -324,7 +335,7 @@ export class SGraphItem extends SObject {
                 continue;
             }
             let ce = SGraphItem.toChildMouseEvent(item, event);
-            if (item.contains(event.x, event.y) && item.onClick(ce)) {
+            if (item.contains(ce.x, ce.y) && item.onClick(ce)) {
                 // 如果点在子项目上且子项目处理了事件
                 return true;
             }
@@ -346,7 +357,7 @@ export class SGraphItem extends SObject {
                 continue;
             }
             let ce = SGraphItem.toChildMouseEvent(item, event);
-            if (item.contains(event.x, event.y) && item.onDoubleClick(ce)) {
+            if (item.contains(ce.x, ce.y) && item.onDoubleClick(ce)) {
                 // 如果点在子项目上且子项目处理了事件
                 return true;
             }
@@ -368,7 +379,7 @@ export class SGraphItem extends SObject {
                 continue;
             }
             let ce = SGraphItem.toChildMouseEvent(item, event);
-            if (item.contains(event.x, event.y) && item.onMouseDown(ce)) {
+            if (item.contains(ce.x, ce.y) && item.onMouseDown(ce)) {
                 // 如果点在子项目上且子项目处理了事件
                 return true;
             }
@@ -401,7 +412,7 @@ export class SGraphItem extends SObject {
                 continue;
             }
             let ce = SGraphItem.toChildMouseEvent(item, event);
-            if (item.contains(event.x, event.y) && item.onMouseMove(ce)) {
+            if (item.contains(ce.x, ce.y) && item.onMouseMove(ce)) {
                 // 如果点在子项目上且子项目处理了事件
                 return true;
             }
@@ -413,10 +424,11 @@ export class SGraphItem extends SObject {
             this._isMoving
         ) {
             let old = new SPoint(this.pos.x, this.pos.y);
-            this.moveTo(
-                this.pos.x + event.x - this._mouseDownPos.x,
-                this.pos.y + event.y - this._mouseDownPos.y
+            const mp = this.toParentChange(
+                event.x - this._mouseDownPos.x,
+                event.y - this._mouseDownPos.y
             );
+            this.moveTo(this.pos.x + mp.x, this.pos.y + mp.y);
             this.$emit("onMove", old, this.pos);
         }
 
@@ -448,7 +460,7 @@ export class SGraphItem extends SObject {
                 continue;
             }
             let ce = SGraphItem.toChildMouseEvent(item, event);
-            if (item.contains(event.x, event.y) && item.onMouseUp(ce)) {
+            if (item.contains(ce.x, ce.y) && item.onMouseUp(ce)) {
                 // 如果点在子项目上且子项目处理了事件
                 return true;
             }
@@ -491,7 +503,7 @@ export class SGraphItem extends SObject {
                 continue;
             }
             let ce = SGraphItem.toChildMouseEvent(item, event);
-            if (item.contains(event.x, event.y) && item.onContextMenu(ce)) {
+            if (item.contains(ce.x, ce.y) && item.onContextMenu(ce)) {
                 // 如果点在子项目上且子项目处理了事件
                 return true;
             }
@@ -559,8 +571,24 @@ export class SGraphItem extends SObject {
         event: SMouseEvent
     ): SMouseEvent {
         let ce = new SMouseEvent(event);
-        ce.x = (event.x - child.x) / child.scale;
-        ce.y = (event.y - child.y) / child.scale;
+        ce.matrix.translateSelf(child.x, child.y);
+        ce.matrix.scaleSelf(child.scale, child.scale);
+        ce.matrix.rotateSelf(0, 0, child.rolate);
+
+        if (!child.isTransform) {
+            let x0 = ce.matrix.e;
+            let y0 = ce.matrix.f;
+            ce.matrix = new DOMMatrix();
+            ce.matrix.translateSelf(x0, y0);
+        }
+
+        const mp = new DOMPoint(event.offsetX, event.offsetY).matrixTransform(
+            ce.matrix.inverse()
+        );
+
+        ce.x = mp.x;
+        ce.y = mp.y;
+
         return ce;
     } // Function toChildMouseEvent()
 
@@ -585,6 +613,22 @@ export class SGraphItem extends SObject {
     } // Function grabItem
 
     /**
+     * 计算点在父节点的位置
+     *
+     * @param   x       X轴
+     * @param   y       Y轴
+     * @return  在父节点的位置
+     */
+    private toParentChange(x: number, y: number): SPoint {
+        const m = new DOMMatrix();
+        m.scaleSelf(this.scale, this.scale);
+        m.rotateSelf(this.rolate);
+
+        const mp = new DOMPoint(x, y).matrixTransform(m);
+        return new SPoint(mp.x, mp.y);
+    }
+
+    /**
      * 判断是否处理事件
      *
      * @return  true: 处理事件,否则不处理

+ 18 - 2
saga-web-graph/src/SGraphView.ts

@@ -406,8 +406,24 @@ export class SGraphView extends SCanvasView {
      */
     private toSceneMotionEvent(event: MouseEvent): SMouseEvent {
         let se = new SMouseEvent(event);
-        se.x = (se.x - this.origin.x) / this.scale;
-        se.y = (se.y - this.origin.y) / this.scale;
+        se.matrix.translateSelf(this.origin.x, this.origin.y);
+        se.matrix.scaleSelf(this.scale, this.scale);
+
+        const mp = new DOMPoint(event.offsetX, event.offsetY).matrixTransform(
+            se.matrix.inverse()
+        );
+
+        se.x = mp.x;
+        se.y = mp.y;
+
+        // se.x =
+        //     event.offsetX * se.matrix.a +
+        //     event.offsetY * se.matrix.c +
+        //     se.matrix.e;
+        // se.y =
+        //     event.offsetX * se.matrix.b +
+        //     event.offsetY * se.matrix.d +
+        //     se.matrix.f;
         return se;
     } // Function toSceneMotionEvent()
 } // Class SGraphyView