Explorar el Código

绘制直线item添加;spath更改

haojianlong hace 4 años
padre
commit
ca7d94cd56

+ 2 - 2
package.json

@@ -32,8 +32,8 @@
     },
     "dependencies": {
         "@saga-web/base": "2.1.27",
-        "@saga-web/draw": "2.1.108",
-        "@saga-web/graph": "2.1.127",
+        "@saga-web/draw": "2.1.109",
+        "@saga-web/graph": "2.1.128",
         "axios": "^0.18.0",
         "pako": "^1.0.10",
         "poly-decomp": "^0.3.0",

+ 1 - 1
src/FloorScene.ts

@@ -279,7 +279,7 @@ export class FloorScene extends SGraphScene {
      *
      *  @param  url     请求路径
      */
-    getFloorData(url: string, data: { ModelId: string }) {
+    getFloorData(url: string, data: { ModelId: string }): Promise<any> {
         let that = this;
         return new Promise((resolve, reject) => {
             Axios({

+ 39 - 0
src/enums/SItemStatus.ts

@@ -0,0 +1,39 @@
+/*
+ * *********************************************************************************************************************
+ *
+ *          !!
+ *        .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.
+ *
+ * *********************************************************************************************************************
+ */
+
+/**
+ * item 状态
+ *
+ * @author  郝建龙 <haojianlong@sagacloud.cn>
+ */
+export enum SItemStatus {
+    /** 标准状态 */
+    Normal,
+    /** 编辑状态 */
+    Edit,
+    /** 创建态 */
+    Create
+}

+ 3 - 1
src/index.ts

@@ -20,6 +20,7 @@ import { ZoneScene } from "./ZoneScene";
 import { Opt } from "./types/Opt";
 import { SImageShowType } from "./enums/SImageShowType";
 import { STextOrigin } from "./enums/STextOrigin";
+import { EditLineItem } from "./items/EditLineItem";
 
 export {
     FloorScene,
@@ -46,5 +47,6 @@ export {
     RectSelectItem,
     LikeSpaceItem,
     SImageShowType,
-    STextOrigin
+    STextOrigin,
+    EditLineItem
 };

+ 578 - 0
src/items/EditLineItem.ts

@@ -0,0 +1,578 @@
+import {
+    SColor,
+    SLine,
+    SPainter,
+    SPoint,
+    SRect,
+    STextAlign
+} from "@saga-web/draw";
+import { SMouseButton, SMouseEvent, SUndoStack } from "@saga-web/base";
+import { SMathUtil } from "../utils/SMathUtil";
+import { SGraphItem, SLineStyle } from "@saga-web/graph";
+import { SItemStatus } from "../enums/SItemStatus";
+
+/**
+ * 直线 item
+ *
+ * @author 郝建龙 <haojianlong@sagacloud.cn>
+ */
+export class EditLineItem extends SGraphItem {
+    /** 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 _line: SPoint[] = [];
+    get line(): SPoint[] {
+        return this._line;
+    }
+    set line(arr: SPoint[]) {
+        this._line = arr;
+        this.update();
+    }
+
+    /** 是否完成绘制 */
+    protected _status: SItemStatus = SItemStatus.Normal;
+    get status(): SItemStatus {
+        return this._status;
+    }
+    set status(v: SItemStatus) {
+        this._status = v;
+        // this.undoStack.clear();
+        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 {
+        return this._activeFillColor;
+    }
+    set activeFillColor(v: SColor) {
+        this._activeFillColor = v;
+        this.update();
+    }
+
+    /** 线条宽度 */
+    private _lineWidth: number = 1;
+    get lineWidth(): number {
+        return this._lineWidth;
+    }
+    set lineWidth(v: number) {
+        this._lineWidth = v;
+        this.update();
+    }
+
+    /** 拖动灵敏度 */
+    dis: number = 5;
+
+    /** 拖动灵敏度 */
+    private sceneDis: number = 5;
+
+    /** 当前点索引 */
+    curIndex: number = -1;
+
+    /** 当前点坐标 */
+    private curPoint: SPoint | null = null;
+
+    /** undo/redo 堆栈 */
+    // private undoStack: SUndoStack = new SUndoStack();
+
+    /** 比例尺长度 */
+    private _text: string = "";
+    get text(): string {
+        return this._text;
+    }
+    set text(v: string) {
+        this._text = v;
+    }
+    /** 文本位置 */
+    textPos: SPoint | null = null;
+
+    /** 绘制时需要旋转的角度 */
+    private _ang: number = 0;
+    /** 两端长短 */
+    extremeLen: number = 8;
+
+    /** 线段数组 */
+    lineList: SLine[] = [];
+
+    /**
+     * 构造函数
+     *
+     * @param parent  父级
+     */
+    constructor(parent: SGraphItem | null);
+
+    /**
+     * 构造函数
+     *
+     * @param parent  父级
+     * @param line    坐标集合
+     */
+    constructor(parent: SGraphItem | null, line: SPoint[]);
+
+    /**
+     * 构造函数
+     *
+     * @param parent  父级
+     * @param point   第一个点坐标
+     */
+    constructor(parent: SGraphItem | null, point: SPoint);
+
+    /**
+     * 构造函数
+     *
+     * @param parent    父级
+     * @param line      坐标集合|第一个点坐标
+     */
+    constructor(parent: SGraphItem | null, line?: SPoint | SPoint[]) {
+        super(parent);
+        //  坐标集合存在时
+        if (line) {
+            // 坐标集合出现在 SPoint 的实例对象上
+            if (line instanceof SPoint) {
+                this.line.push(line);
+            } else {
+                // 没有在 SPoint 的实例对象上
+                this.line = line;
+                this.pointChange();
+            }
+        } else {
+            // 坐标集合不存在时
+            this.line = [];
+        }
+    }
+
+    /**
+     * 点发生变化
+     */
+    protected pointChange(): void {
+        if (this.line.length > 1) {
+            const line = new SLine(this.line[0], this.line[1]);
+            const dis = SMathUtil.pointDistance(
+                this.line[0].x,
+                this.line[0].y,
+                this.line[1].x,
+                this.line[1].y
+            );
+            if (line.dx != 0) {
+                const tempFo = Math.atan(line.dy / line.dx);
+                this._ang = line.dx > 0 ? tempFo : tempFo + Math.PI;
+            } else {
+                this._ang = line.dy > 0 ? Math.PI / 2 : (3 * Math.PI) / 2;
+            }
+            this.lineList = [
+                new SLine(0, 0, dis, 0),
+                new SLine(0, this.extremeLen, 0, -this.extremeLen),
+                new SLine(dis, this.extremeLen, dis, -this.extremeLen)
+            ];
+            this.textPos = new SPoint(dis / 2, 0);
+            this.calculate();
+        }
+    }
+
+    /**
+     * 添加点至数组中
+     *
+     * @param p 添加的点
+     */
+    private addPoint(p: SPoint): void {
+        // 坐标集合长度大于2时
+        if (this.line.length < 2) {
+            this.line.push(p);
+            // this.recordAction(SGraphPointListInsert, [this.line, p]);
+        } else {
+            // 坐标集合长度不大于2时
+            this.line[1] = p;
+            // this.recordAction(SGraphPointListInsert, [this.line, p, 1]);
+            this.status = SItemStatus.Normal;
+            this.releaseItem();
+            this.$emit("finishCreated");
+            this.pointChange();
+        }
+        this.update();
+    }
+
+    /**
+     * 鼠标双击事件
+     *
+     * @param event     事件参数
+     * @return 是否处理事件
+     */
+    onDoubleClick(event: SMouseEvent): boolean {
+        // 如果为show状态 双击改对象则需改为编辑状态
+        if (this.status == SItemStatus.Normal) {
+            this.status = SItemStatus.Edit;
+            this.grabItem(this);
+        } else if (this.status == SItemStatus.Edit) {
+            // 处于编辑状态时
+            this.status = SItemStatus.Normal;
+            this.releaseItem();
+        }
+        this.update();
+        return true;
+    }
+
+    /**
+     * 鼠标按下事件
+     *
+     * @param event     鼠标事件
+     * @return 是否处理事件
+     */
+    onMouseDown(event: SMouseEvent): boolean {
+        this.curIndex = -1;
+        this.curPoint = null;
+        // 按下 shiftKey 键
+        if (event.shiftKey) {
+            event = this.compare(event);
+        }
+        // 按下鼠标左键
+        if (event.buttons == SMouseButton.LeftButton) {
+            if (this.status == SItemStatus.Normal) {
+                //标准状态时
+                return super.onMouseDown(event);
+            } else if (this.status == SItemStatus.Edit) {
+                // 编辑状态时
+                // 判断是否点击到端点上(获取端点索引值)
+                this.findNearestPoint(new SPoint(event.x, event.y));
+            } else if (this.status == SItemStatus.Create) {
+                // 创建状态时
+                this.addPoint(new SPoint(event.x, event.y));
+                return true;
+            }
+        }
+
+        return true;
+    }
+
+    /**
+     * 鼠标抬起事件
+     *
+     * @param event     事件参数
+     * @return 是否处理事件
+     */
+    onMouseUp(event: SMouseEvent): boolean {
+        // 处于编辑状态时
+        if (this.status == SItemStatus.Edit) {
+            // 当前点索引大于 -1 时
+            if (this.curIndex > -1) {
+                const p = new SPoint(
+                    this.line[this.curIndex].x,
+                    this.line[this.curIndex].y
+                );
+                // this.recordAction(SGraphPointListUpdate, [
+                //     this.line,
+                //     this.curPoint,
+                //     p,
+                //     this.curIndex
+                // ]);
+            }
+        } else if (this.status == SItemStatus.Normal) {
+            // 标准状态时
+            this.moveToOrigin(this.x, this.y);
+            return super.onMouseUp(event);
+        }
+
+        this.curIndex = -1;
+        this.curPoint = null;
+        return true;
+    }
+
+    /**
+     * 鼠标移动事件
+     *
+     * @param event     事件参数
+     * @return 是否处理事件
+     */
+    onMouseMove(event: SMouseEvent): boolean {
+        // 按下 shiftKey 键
+        if (event.shiftKey) {
+            event = this.compare(event);
+        }
+
+        // 处于创建状态时
+        if (this.status == SItemStatus.Create) {
+            if (this.line[0] instanceof SPoint) {
+                this.line[1] = new SPoint(event.x, event.y);
+                this.pointChange();
+            }
+        } else if (this.status == SItemStatus.Edit) {
+            // 处于编辑状态时
+            // 当前索引不等于 -1 时
+            if (-1 != this.curIndex) {
+                this.line[this.curIndex].x = event.x;
+                this.line[this.curIndex].y = event.y;
+                this.pointChange();
+            }
+        } else {
+            return super.onMouseMove(event);
+        }
+
+        this.update();
+        return true;
+    }
+
+    /**
+     * 获取点击点与 Point[] 中的点距离最近点
+     *
+     * @param p     鼠标点击点
+     */
+    findNearestPoint(p: SPoint): void {
+        // 拖动灵敏度
+        let len = this.sceneDis;
+        for (let i = 0; i < this.line.length; i++) {
+            // 计算点到点距离
+            let dis = SMathUtil.pointDistance(
+                p.x,
+                p.y,
+                this.line[i].x,
+                this.line[i].y
+            );
+            // 点到点的距离大于灵敏度时
+            if (dis < len) {
+                len = dis;
+                this.curIndex = i;
+                this.curPoint = new SPoint(this.line[this.curIndex]);
+            }
+        }
+    }
+
+    /**
+     * 记录相关动作并推入栈中
+     *
+     * @param SGraphCommand 相关命令类
+     * @param any           对应传入参数
+     */
+    // protected recordAction(SGraphCommand: any, any: any[]): void {
+    //     // 记录相关命令并推入堆栈中 todo
+    //     const command = new SGraphCommand(this.scene, this, ...any);
+    //     this.undoStack.push(command);
+    // }
+
+    /**
+     * 移动后处理所有坐标,并肩原点置为场景原点
+     *
+     * @param x     x 坐标
+     * @param y     y 坐标
+     */
+    moveToOrigin(x: number, y: number): void {
+        super.moveToOrigin(x, y);
+        this.line = this.line.map(
+            (t): SPoint => {
+                t.x = t.x + x;
+                t.y = t.y + y;
+                return t;
+            }
+        );
+        this.x = 0;
+        this.y = 0;
+    }
+
+    /**
+     * shift 垂直水平创建或编辑
+     *
+     * @param event     事件
+     * @return 处理后的事件对象
+     */
+    compare(event: SMouseEvent): SMouseEvent {
+        // 线段长度存在时
+        if (this.line.length) {
+            let last = new SPoint(event.x, event.y);
+            // 处于创建状态时
+            if (this.status == SItemStatus.Create) {
+                last = this.line[0];
+            } else if (this.status == SItemStatus.Edit) {
+                // 处于编辑状态时
+                // 当前索引等于 1 时
+                if (this.curIndex == 1) {
+                    last = this.line[0];
+                } else if (this.curIndex == 0) {
+                    // 当前索引等于 0 时
+                    last = this.line[1];
+                }
+            }
+            const dx = Math.abs(event.x - last.x);
+            const dy = Math.abs(event.y - last.y);
+            if (dy > dx) {
+                event.x = last.x;
+            } else {
+                event.y = last.y;
+            }
+        }
+
+        return event;
+    }
+
+    /**
+     * 判断点是否在区域内
+     *
+     * @param x     x 坐标
+     * @param y     y 坐标
+     * @return 是否包含
+     */
+    contains(x: number, y: number): boolean {
+        // 线段长度大于 2 时
+        if (this.line.length == 2) {
+            let p = new SPoint(x, y);
+            // 计算点到线段垂线与线段的交点
+            if (
+                SMathUtil.pointToLine(p, new SLine(this.line[0], this.line[1]))
+                    .MinDis < this.dis
+            ) {
+                return true;
+            }
+        }
+
+        return false;
+    }
+
+    // /**
+    //  * 撤销操作
+    //  */
+    // undo(): void {
+    //     // 处于标准状态时
+    //     if (this.status != SItemStatus.Normal) {
+    //         this.undoStack.undo();
+    //     }
+    // }
+
+    // /**
+    //  * 重做操作
+    //  */
+    // redo(): void {
+    //     // 处于标准状态时
+    //     if (this.status != SItemStatus.Normal) {
+    //         this.undoStack.redo();
+    //     }
+    // }
+
+    /**
+     * 取消操作 item 事件
+     */
+    cancelOperate(): void {
+        // 处于创建状态时
+        if (this.status == SItemStatus.Create) {
+            this.parent = null;
+            this.releaseItem();
+        } else if (this.status == SItemStatus.Edit) {
+            // 处于编辑状态时
+            this.status = SItemStatus.Normal;
+            this.releaseItem();
+        }
+    }
+
+    /**
+     * 计算边界值
+     */
+    calculate(): void {
+        // 线段长度存在时
+        if (this.line.length) {
+            this.minX = this.line[0].x;
+            this.maxX = this.line[0].x;
+            this.minY = this.line[0].y;
+            this.maxY = this.line[0].y;
+            this.line.forEach((it): void => {
+                let x = it.x,
+                    y = it.y;
+
+                // 如果数据 x 坐标小于 x 坐标最小值
+                if (x < this.minX) {
+                    this.minX = x;
+                }
+
+                // 如果数据 y 坐标小于 y 坐标最小值
+                if (y < this.minY) {
+                    this.minY = y;
+                }
+
+                // 如果数据 x 坐标大于 x 坐标最小值
+                if (x > this.maxX) {
+                    this.maxX = x;
+                }
+
+                // 如果数据 y 坐标大于 y 坐标最小值
+                if (y > this.maxY) {
+                    this.maxY = y;
+                }
+            });
+        }
+    }
+
+    /**
+     * Item 对象边界区域
+     *
+     * @return 边界区域
+     */
+    boundingRect(): SRect {
+        this.calculate();
+        return new SRect(
+            this.minX,
+            this.minY,
+            this.maxX - this.minX,
+            this.maxY - this.minY
+        );
+    }
+
+    /**
+     * Item 绘制操作
+     *
+     * @param painter   绘制对象
+     */
+    onDraw(painter: SPainter): void {
+        // 如果线段存在
+        if (this.line.length) {
+            painter.save();
+            painter.pen.lineWidth = painter.toPx(this.lineWidth);
+            painter.translate(this.line[0].x, this.line[0].y);
+            painter.rotate((this._ang * 180) / Math.PI);
+            painter.pen.color = this.strokeColor;
+            painter.brush.color = this.fillColor;
+            this.lineList.forEach(t => {
+                painter.drawLine(t);
+            });
+            if (this.text && this.textPos) {
+                painter.font.textAlign = STextAlign.Center;
+                painter.brush.color = SColor.Black;
+                painter.pen.color = SColor.White;
+                painter.pen.lineWidth = painter.toPx(8);
+                painter.drawText(this.text, this.textPos.x, this.textPos.y);
+            }
+            painter.restore();
+        }
+    }
+}

+ 2 - 2
src/items/LikeSpaceItem.ts

@@ -22,7 +22,7 @@ import { SGraphItem } from "@saga-web/graph/lib";
 import {
     SColor,
     SPainter,
-    SPath2D,
+    SPath,
     SPoint,
     SPolygonUtil,
     SRect
@@ -51,7 +51,7 @@ export class LikeSpaceItem extends SGraphItem {
     /** Y坐标最大值  */
     maxY = Number.MIN_SAFE_INTEGER;
     /** path对象      */
-    private path = new SPath2D();
+    private path = new SPath();
     /** 高亮状态    */
     private _highLightFlag: boolean = false;
     get highLightFlag(): boolean {

+ 1 - 0
src/items/SImageItem.ts

@@ -170,6 +170,7 @@ export class SImageItem extends SObjectItem {
      */
     private isUrlIdentical(imgUrl: string): boolean {
         if (this.url.indexOf("://") == -1) {
+            // eslint-disable-next-line max-len
             const reg = /^\s*data:([a-z]+\/[a-z0-9-+.]+(;[a-z-]+=[a-z0-9-]+)?)?(;base64)?,([a-z0-9!$&',()*+;=\-._~:@\/?%\s]*?)\s*$/i;
             if (reg.test(this.url)) {
                 // url是base64地址

+ 3 - 3
src/items/SceneMarkItem.ts

@@ -24,7 +24,7 @@ import {
     SColor,
     SLineCapStyle,
     SPainter,
-    SPath2D,
+    SPath,
     SPoint,
     SPolygonUtil,
     SRect
@@ -54,7 +54,7 @@ export class SceneMarkItem extends SGraphItem {
     /** 鼠标移动点  */
     private lastPoint = new SPoint();
     /** 蒙版       */
-    private mask = new SPath2D();
+    private mask = new SPath();
 
     /**
      * 构造函数
@@ -199,7 +199,7 @@ export class SceneMarkItem extends SGraphItem {
             // @ts-ignore
             this.scene.isMarking = false;
         }
-        this.mask = new SPath2D();
+        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);

+ 2 - 2
src/items/SpaceItem.ts

@@ -22,7 +22,7 @@ import { SGraphItem } from "@saga-web/graph/lib";
 import {
     SColor,
     SPainter,
-    SPath2D,
+    SPath,
     SPoint,
     SPolygonUtil,
     SRect,
@@ -52,7 +52,7 @@ export class SpaceItem extends SGraphItem {
     /** Y坐标最大值  */
     maxY = Number.MIN_SAFE_INTEGER;
     /** path对象      */
-    private path = new SPath2D();
+    private path = new SPath();
     /** 高亮状态    */
     private _highLightFlag: boolean = false;
     get highLightFlag(): boolean {

+ 3 - 3
src/items/ZoneItem.ts

@@ -22,7 +22,7 @@ import { SGraphItem } from "@saga-web/graph/lib";
 import {
     SColor,
     SPainter,
-    SPath2D,
+    SPath,
     SPoint,
     SPolygonUtil,
     SRect
@@ -52,7 +52,7 @@ export class ZoneItem extends SGraphItem {
     /** Y坐标最大值  */
     private maxY = Number.MIN_SAFE_INTEGER;
     /** path    */
-    private pathList: SPath2D[] = [];
+    private pathList: SPath[] = [];
     /** 点击位置坐标  */
     private clickPoint: SPoint | undefined;
     /** 选中时的颜色  */
@@ -116,7 +116,7 @@ export class ZoneItem extends SGraphItem {
             this.maxY = this.minY;
             // 处理轮廓点数组,同时计算最大最小值
             this.pointArr = tempArr.map((t): SPoint[][] => {
-                let sPath = new SPath2D();
+                let sPath = new SPath();
                 let tempArr = t.map((it): SPoint[] => {
                     let array = it.map(
                         (item): SPoint => {