Bläddra i källkod

graph:feat:增加样式 item 线宽是否为像素属性;view增加适配 绘制区域比例;big:feat:增加蒙版item;fix:线段item从styleitem派生

haojianlong 4 år sedan
förälder
incheckning
c8020fee4f

+ 3 - 1
persagy-web-big/src/index.ts

@@ -48,6 +48,7 @@ import unzip from "./utils/unzip";
 import unzipBase64 from "./utils/unzipBase64";
 import { SPipeItem } from "./items/SPipeItem";
 import { SEquipItem } from "./items/SEquipItem";
+import { SSceneMaskItem } from "./items/SSceneMaskItem";
 
 export {
     SLayerItem,
@@ -73,5 +74,6 @@ export {
     unzip,
     unzipBase64,
     SPipeItem,
-    SEquipItem
+    SEquipItem,
+    SSceneMaskItem
 };

+ 2 - 45
persagy-web-big/src/items/SLineItem.ts

@@ -34,13 +34,14 @@ import {
     SGraphPointListUpdate,
     SLineStyle
 } from "@persagy-web/graph";
+import { SGraphStyleItem } from "@persagy-web/graph/lib";
 
 /**
  * 直线 item
  *
  * @author 郝建龙 <haojianlong@sagacloud.cn>
  */
-export class SLineItem extends SGraphItem {
+export class SLineItem extends SGraphStyleItem {
     /** X 坐标最小值 */
     private minX = Number.MAX_SAFE_INTEGER;
     /** X 坐标最大值 */
@@ -73,39 +74,6 @@ export class SLineItem extends SGraphItem {
         this.update();
     }
 
-    /** 线条颜色 */
-    private _strokeColor: SColor = SColor.Black;
-    get strokeColor(): SColor {
-        return this._strokeColor;
-    }
-
-    set strokeColor(v: SColor) {
-        this._strokeColor = v;
-        this.update();
-    }
-
-    /** 线条样式 */
-    private _lineStyle: SLineStyle = SLineStyle.Solid;
-    get lineStyle(): SLineStyle {
-        return this._lineStyle;
-    }
-
-    set lineStyle(v: SLineStyle) {
-        this._lineStyle = v;
-        this.update();
-    }
-
-    /** 端点填充色 */
-    private _fillColor: SColor = SColor.White;
-    get fillColor(): SColor {
-        return this._fillColor;
-    }
-
-    set fillColor(v: SColor) {
-        this._fillColor = v;
-        this.update();
-    }
-
     /** 选中端点填充色 */
     private _activeFillColor: SColor = new SColor("#2196f3");
     get activeFillColor(): SColor {
@@ -117,17 +85,6 @@ export class SLineItem extends SGraphItem {
         this.update();
     }
 
-    /** 线条宽度 */
-    private _lineWidth: number = 1;
-    get lineWidth(): number {
-        return this._lineWidth;
-    }
-
-    set lineWidth(v: number) {
-        this._lineWidth = v;
-        this.update();
-    }
-
     /** 拖动灵敏度 */
     dis: number = 5;
 

+ 269 - 0
persagy-web-big/src/items/SSceneMaskItem.ts

@@ -0,0 +1,269 @@
+/*
+ * *********************************************************************************************************************
+ *
+ *          !!
+ *        .F88X
+ *        X8888Y
+ *      .}888888N;
+ *        i888888N;        .:!              .I$WI:
+ *          R888888I      .'N88~            i8}+8Y&8"l8i$8>8W~'>W8}8]KW+8IIN"8&
+ *          .R888888I    .;N8888~          .X8'  "8I.!,/8"  !%NY8`"8I8~~8>,88I
+ *            +888888N;  .8888888Y                                  "&&8Y.}8,
+ *            ./888888N;  .R888888Y        .'}~    .>}'.`+>  i}!    "i'  +/'  .'i~  !11,.:">,  .~]!  .i}i
+ *              ~888888%:  .I888888l      .]88~`1/iY88Ii+1'.R$8$8]"888888888>  Y8$  W8E  X8E  W8888'188Il}Y88$*
+ *              18888888    E8888881    .]W%8$`R8X'&8%++N8i,8N%N8+l8%`  .}8N:.R$RE%N88N%N$K$R  188,FE$8%~Y88I
+ *            .E888888I  .i8888888'      .:$8I;88+`E8R:/8N,.>881.`$8E/1/]N8X.Y8N`"KF&&FK!'88*."88K./$88%RN888+~
+ *            8888888I  .,N888888~        ~88i"8W,!N8*.I88.}888%F,i$88"F88"  888:E8X.>88!i88>`888*.}Fl1]*}1YKi'
+ *          i888888N'      I888Y          ]88;/EX*IFKFK88X  K8R  .l8W  88Y  ~88}'88E&%8W.X8N``]88!.$8K  .:W8I
+ *        .i888888N;        I8Y          .&8$  .X88!  i881.:%888>I88  ;88]  +88+.';;;;:.Y88X  18N.,88l  .+88/
+ *      .:R888888I
+ *      .&888888I                                          Copyright (c) 2009-2020.  博锐尚格科技股份有限公司
+ *        ~8888'
+ *        .!88~                                                                     All rights reserved.
+ *
+ * *********************************************************************************************************************
+ */
+
+import { SGraphStyleItem } from "@persagy-web/graph";
+import {
+    SLineCapStyle,
+    SPainter,
+    SPath,
+    SPoint,
+    SPolygonUtil,
+    SRect
+} from "@persagy-web/draw";
+import { SGraphItem } from "@persagy-web/graph/lib";
+import { ItemOrder } from "../config/ItemOrder";
+import { SItemStatus } from "..";
+import { SMouseEvent } from "@persagy-web/base";
+import { SMathUtil } from "@persagy-web/graph/lib/utils/SMathUtil";
+
+export class SSceneMaskItem extends SGraphStyleItem {
+    /** 轮廓线坐标 */
+    outline: SPoint[] = [];
+    /** X坐标最小值 */
+    private minX = Number.MAX_SAFE_INTEGER;
+    /** X坐标最大值 */
+    private maxX = Number.MIN_SAFE_INTEGER;
+    /** Y坐标最小值 */
+    private minY = Number.MAX_SAFE_INTEGER;
+    /** Y坐标最大值 */
+    private maxY = Number.MIN_SAFE_INTEGER;
+    /** 鼠标移动点 */
+    private lastPoint = new SPoint();
+    /** 蒙版 */
+    private mask = new SPath();
+    /** 是否完成绘制 */
+    protected _status: SItemStatus = SItemStatus.Normal;
+    get status(): SItemStatus {
+        return this._status;
+    }
+    set status(v: SItemStatus) {
+        this._status = v;
+        this.update();
+    }
+
+    /**
+     * 构造函数
+     *
+     * @param parent    指向父对象
+     * @param data      蒙版起点数据
+     */
+    constructor(parent: SGraphItem | null, data: SPoint);
+
+    /**
+     * 构造函数
+     *
+     * @param parent    指向父对象
+     * @param data      蒙版轮廓线数据
+     */
+    constructor(parent: SGraphItem | null, data: SPoint[]);
+
+    /**
+     * 构造函数
+     *
+     * @param parent    指向父对象
+     * @param data      蒙版起点数据 | 蒙版轮廓线数据
+     */
+    constructor(parent: SGraphItem | null, data: SPoint[] | SPoint) {
+        super(parent);
+        if (data instanceof Array) {
+            this.outline = data;
+            this.createMask();
+            this.outline.forEach(it => {
+                let x = it.x,
+                    y = it.y;
+                if (x < this.minX) {
+                    this.minX = x;
+                }
+                if (y < this.minY) {
+                    this.minY = y;
+                }
+                if (x > this.maxX) {
+                    this.maxX = x;
+                }
+                if (y > this.maxY) {
+                    this.maxY = y;
+                }
+            });
+        } else {
+            this.outline.push(data);
+            this.lastPoint = data;
+            this.minY = data.y;
+            this.maxY = data.y;
+            this.minX = data.x;
+            this.maxX = data.x;
+        }
+        this.zOrder = ItemOrder.sceneMarkOrder;
+    }
+
+    /**
+     * 创建蒙版
+     */
+    createMask(): void {
+        this.status = SItemStatus.Normal;
+        this.releaseItem();
+        this.$emit("finishCreated");
+        this.mask = new SPath();
+        this.mask.moveTo(Number.MIN_SAFE_INTEGER, Number.MIN_SAFE_INTEGER);
+        this.mask.lineTo(Number.MAX_SAFE_INTEGER, Number.MIN_SAFE_INTEGER);
+        this.mask.lineTo(Number.MAX_SAFE_INTEGER, Number.MAX_SAFE_INTEGER);
+        this.mask.lineTo(Number.MIN_SAFE_INTEGER, Number.MAX_SAFE_INTEGER);
+        this.mask.lineTo(Number.MIN_SAFE_INTEGER, Number.MIN_SAFE_INTEGER);
+
+        let antiArr = this.outline.concat([]);
+        // (计算基于数学坐标系统,在绘图坐标系由于y轴方向相反结果也要取反)
+        if (SPolygonUtil.clockDir(antiArr) > 0) {
+            antiArr = antiArr.reverse();
+        }
+        this.mask.polygon(antiArr);
+        this.update();
+    }
+
+    /**
+     * 外接矩阵
+     */
+    boundingRect(): SRect {
+        return new SRect(
+            this.minX,
+            this.minY,
+            this.maxX - this.minX,
+            this.maxY - this.minY
+        );
+    }
+
+    /**
+     * 判断点是否在区域内
+     *
+     * @param x
+     * @param y
+     */
+    contains(x: number, y: number): boolean {
+        let arr = this.outline;
+        return !SPolygonUtil.pointIn(x, y, arr);
+    }
+
+    /**
+     * 鼠标按下事件
+     *
+     * @param	event         事件参数
+     * @return	boolean
+     */
+    onMouseDown(event: SMouseEvent): boolean {
+        if (this.status == SItemStatus.Create && event.buttons == 1) {
+            if (
+                this.lastPoint.x == this.outline[0].x &&
+                this.lastPoint.y == this.outline[0].y &&
+                this.outline.length >= 3
+            ) {
+                this.createMask();
+                return true;
+            }
+            let p = new SPoint(event.x, event.y);
+            let x = p.x,
+                y = p.y;
+            this.lastPoint.x = x;
+            this.lastPoint.y = y;
+            this.outline.push(p);
+            if (x < this.minX) {
+                this.minX = x;
+            }
+            if (y < this.minY) {
+                this.minY = y;
+            }
+            if (x > this.maxX) {
+                this.maxX = x;
+            }
+            if (y > this.maxY) {
+                this.maxY = y;
+            }
+        }
+        this.update();
+        return true;
+    } // Function onMouseDown()
+
+    /**
+     * 鼠标移动事件
+     *
+     * @param	event         事件参数
+     * @return	boolean
+     */
+    onMouseMove(event: SMouseEvent): boolean {
+        if (this.status == SItemStatus.Create) {
+            this.lastPoint = new SPoint(event.x, event.y);
+            if (this.outline.length >= 3) {
+                let le = SMathUtil.pointDistance(
+                    this.lastPoint.x,
+                    this.lastPoint.y,
+                    this.outline[0].x,
+                    this.outline[0].y
+                );
+                // @ts-ignore
+                let scale = this.parent.scene.view.scale;
+                if (le * scale < 30) {
+                    this.lastPoint.x = this.outline[0].x;
+                    this.lastPoint.y = this.outline[0].y;
+                }
+            }
+        }
+        this.update();
+        return true;
+    } // Function onMouseMove()
+
+    /***
+     * 键盘按键弹起事件
+     *
+     * @param	event         事件参数
+     */
+    onKeyUp(event: KeyboardEvent): void {
+        if (event.keyCode == 13 && this.outline.length >= 3) {
+            this.createMask();
+        }
+    } // Function onKeyUp()
+
+    /**
+     * Item绘制操作
+     *
+     * @param   painter       painter对象
+     */
+    onDraw(painter: SPainter): void {
+        painter.pen.lineCapStyle = SLineCapStyle.Square;
+        painter.pen.color = this.strokeColor;
+        painter.brush.color = this.fillColor;
+        if (this.widthIsPx) {
+            painter.pen.lineWidth = painter.toPx(this.lineWidth);
+        } else {
+            painter.pen.lineWidth = this.lineWidth;
+        }
+        if (this.status == SItemStatus.Normal) {
+            painter.drawPath(this.mask);
+        } else if (this.status == SItemStatus.Create) {
+            painter.drawPolyline(this.outline);
+            painter.drawLine(
+                this.outline[this.outline.length - 1],
+                this.lastPoint
+            );
+        }
+    }
+}

+ 1 - 1
persagy-web-graph/package.json

@@ -1,6 +1,6 @@
 {
     "name": "@persagy-web/graph",
-    "version": "2.2.30",
+    "version": "2.2.31",
     "description": "博锐尚格二维图形引擎。",
     "main": "lib/index.js",
     "types": "lib/index.d.js",

+ 20 - 11
persagy-web-graph/src/SGraphView.ts

@@ -123,34 +123,41 @@ export class SGraphView extends SCanvasView {
 
     /**
      * 适配视图到视图
+     *
+     * @param scale 适配所占绘制区域百分比
      */
-    fitSceneToView(): void {
+    fitSceneToView(scale: number = 0.8): void {
         if (null == this.scene) {
             return;
         }
 
         // 场景中无对象
         let rect = this.scene.allItemRect();
-        this.fitRectToSize(this.width, this.height, rect);
+        this.fitRectToSize(this.width, this.height, rect, scale);
     }
 
     /**
      * 适配选中的对象在视图中可见
+     *
+     * @param scale 适配所占绘制区域百分比
      */
-    fitSelectedToView(): void {
+    fitSelectedToView(scale: number = 0.8): void {
         if (null == this.scene) {
             return;
         }
 
         // 场景中无对象
         let rect = this.scene.selectedItemRect();
-        this.fitRectToSize(this.width, this.height, rect);
+        this.fitRectToSize(this.width, this.height, rect, scale);
     }
 
     /**
      * 适配任意对象在视图中可见
+     *
+     * @param itemList 所有要参与适配的 item
+     * @param scale    适配所占绘制区域百分比
      */
-    fitItemToView(itemList: SGraphItem[]): void {
+    fitItemToView(itemList: SGraphItem[], scale: number = 0.8): void {
         if (null == this.scene) {
             return;
         }
@@ -167,7 +174,7 @@ export class SGraphView extends SCanvasView {
             }
         }
         // 场景中无对象
-        this.fitRectToSize(this.width, this.height, rect);
+        this.fitRectToSize(this.width, this.height, rect, scale);
     }
 
     /**
@@ -471,21 +478,23 @@ export class SGraphView extends SCanvasView {
     /**
      * 适配场景在视图中可见
      *
-     * @param width       宽度
-     * @param height      高度
-     * @param rect        对象的矩阵大小
+     * @param width     宽度
+     * @param height    高度
+     * @param rect      对象的矩阵大小
+     * @param scale     适配后所占屏幕百分比(0 - 1 之间的数)
      */
     private fitRectToSize(
         width: number,
         height: number,
-        rect: SRect | null
+        rect: SRect | null,
+        scale: number = 0.8
     ): void {
         // 未设置场景
         if (null == rect || !rect.isValid()) {
             return;
         }
 
-        this.scale = Math.min(width / rect.width, height / rect.height) * 0.8;
+        this.scale = Math.min(width / rect.width, height / rect.height) * scale;
 
         // 计算场景中心点
         let center = rect.center();

+ 8 - 0
persagy-web-graph/src/items/SGraphStyleItem.ts

@@ -74,6 +74,14 @@ export class SGraphStyleItem extends SGraphItem {
         this.update();
     } // Set lineWidth
 
+    /** 宽度是否像素 */
+    widthIsPx: boolean = false;
+
+    /**
+     * 构造函数
+     *
+     * @param parent    父级
+     */
     constructor(parent: SGraphItem | null = null) {
         super(parent);
     }