Explorar o código

划分item添加;场景吸附功能;点击空白业务空间颜色变化bug

haojianlong %!s(int64=4) %!d(string=hai) anos
pai
achega
576b1d76d7

+ 2 - 1
package.json

@@ -33,7 +33,8 @@
     "vue-router": "^3.4.8",
     "vue-svgicon": "^3.2.9",
     "vuex": "^3.5.1",
-    "vuex-module-decorators": "^1.0.1"
+    "vuex-module-decorators": "^1.0.1",
+    "polybooljs": "1.2.0"
   },
   "devDependencies": {
     "@babel/core": "^7.12.10",

+ 235 - 0
src/utils/graph/DivideFloorScene.ts

@@ -0,0 +1,235 @@
+import { SMouseEvent } from "@persagy-web/base/lib";
+import { SMathUtil } from "@persagy-web/big/lib/utils/SMathUtil";
+import { SPoint, SRect } from "@persagy-web/draw/lib";
+import { FloorScene } from "./FloorScene";
+import { HighlightItem } from "./HighlightItem";
+import { ShadeItem } from "./ShadeItem";
+
+export class DivideFloorScene extends FloorScene {
+    /** 划分item  */
+    cutItem: ShadeItem | null = null;
+    /** 是否开启切分  */
+    isCutting: boolean = false;
+
+    /** 是否开启吸附  */
+    private _isAbsorbing: boolean = true;
+    get isAbsorbing(): boolean {
+        return this._isAbsorbing;
+    } // Get isAbsorbing
+    set isAbsorbing(v: boolean) {
+        this._isAbsorbing = v;
+    } // Set isAbsorbing
+
+    /** 高亮item  */
+    highLight: HighlightItem | null = null;
+
+    /**
+     * 清除划分区域
+     */
+    clearCut(): void {
+        if (this.cutItem) {
+            this.grabItem = null;
+            this.removeItem(this.cutItem);
+            this.cutItem = null;
+            this.isCutting = false;
+            this.view && this.view.update();
+        }
+    } // Function clearCut()
+
+    /**
+    * 鼠标按下事件
+    *
+    * @param   event   保存事件参数
+    * @return  boolean
+    */
+    onMouseDown(event: SMouseEvent): boolean {
+        if (event.buttons == 1) {
+            if (this.isCutting) {
+                // 判断是否开启吸附,并且有吸附的点
+                if (
+                    this.isAbsorbing &&
+                    this.highLight &&
+                    this.highLight.visible
+                ) {
+                    event.x = this.highLight.point.x;
+                    event.y = this.highLight.point.y;
+                }
+                if (this.cutItem) {
+                    return this.cutItem.onMouseDown(event);
+                } else {
+                    let point = new SPoint(event.x, event.y);
+                    let cut = new ShadeItem(null, point);
+                    this.addItem(cut);
+                    this.cutItem = cut;
+                    this.grabItem = cut;
+                    return true;
+                }
+            }
+        }
+        return super.onMouseDown(event)
+    }
+
+    /**
+     *  吸附空间
+     *
+     *  @param  event   鼠标事件对象
+     */
+    onMouseMove(event: SMouseEvent): boolean {
+        super.onMouseMove(event);
+        if (this.isAbsorbing) {
+            if (!this.highLight) {
+                this.highLight = new HighlightItem(null);
+                this.addItem(this.highLight);
+            }
+            this.highLight.visible = false;
+            // if (!this.absorbShade(event)) {
+            this.absorbSpace(event);
+            // }
+        }
+        return false;
+    } // Function onMouseMove()
+
+    /**
+     *  吸附空间
+     *
+     *  @param  event   鼠标事件对象
+     *  @return boolean 是否找到吸附的对象
+     */
+    absorbSpace(event: SMouseEvent): boolean {
+        if (!this.highLight) {
+            return false;
+        }
+        let absorbLen = 1000;
+        if (this.view) {
+            absorbLen = 10 / this.view.scale;
+        }
+        let P = this.absorbSpacePoint(event, absorbLen);
+        if (P.Point) {
+            this.highLight.distance = P.MinDis;
+            this.highLight.point = new SPoint(P.Point.X, -P.Point.Y);
+            this.highLight.visible = true;
+            return true;
+        } else {
+            let L = this.absorbSpaceLine(event, absorbLen);
+            if (L.Line && L.Point) {
+                this.highLight.distance = L.MinDis;
+                this.highLight.point = L.Point;
+                this.highLight.line = L.Line;
+                this.highLight.visible = true;
+                return true;
+            }
+            return false;
+        }
+    } // Function absorbSpace()
+
+    /**
+     *  吸附空间点
+     *
+     *  @param  event       鼠标事件对象
+     *  @param  absorbLen   吸附距离
+     *  @return MinDis      吸附的点
+     */
+    absorbSpacePoint(event: SMouseEvent, absorbLen: number): any {
+        let minPointDis = Number.MAX_SAFE_INTEGER;
+        let Point;
+        this.spaceList.map((space): void => {
+            if (
+                DivideFloorScene.isPointInAbsorbArea(
+                    new SPoint(event.x, event.y),
+                    space.minX,
+                    space.maxX,
+                    space.minY,
+                    space.maxY
+                )
+            ) {
+                space.data.OutLine.forEach((item): void => {
+                    let minDis = SMathUtil.getMinDisPoint(
+                        new SPoint(event.x, event.y),
+                        item
+                    );
+                    if (
+                        minDis &&
+                        minDis.MinDis < absorbLen &&
+                        minDis.MinDis < minPointDis
+                    ) {
+                        minPointDis = minDis.MinDis;
+                        Point = minDis.Point;
+                    }
+                });
+            }
+        });
+        return {
+            MinDis: minPointDis,
+            Point: Point
+        };
+    } // Function absorbSpacePoint()
+
+    /**
+     *  点是否在吸附区域内
+     *
+     *  @param  p       要判断的点
+     *  @param  minX    空间区域
+     *  @param  minY    空间区域
+     *  @param  maxX    空间区域
+     *  @param  maxY    空间区域
+     */
+    static isPointInAbsorbArea(
+        p: SPoint,
+        minX: number,
+        maxX: number,
+        minY: number,
+        maxY: number
+    ): boolean {
+        let rect = new SRect(
+            minX - 1000,
+            minY - 1000,
+            maxX - minX + 2000,
+            maxY - minY + 2000
+        );
+        return rect.contains(p.x, p.y);
+    } // Function isPointInAbsorbArea()
+
+    /**
+         *  吸附空间线
+         *
+         *  @param  event       鼠标事件对象
+         *  @param  absorbLen   吸附距离
+         *  @return PointToLine 吸附的线
+         */
+    absorbSpaceLine(event: SMouseEvent, absorbLen: number): any {
+        let minPointDis = Number.MAX_SAFE_INTEGER;
+        let Point, Line;
+        this.spaceList.forEach((space): void => {
+            if (
+                DivideFloorScene.isPointInAbsorbArea(
+                    new SPoint(event.x, event.y),
+                    space.minX,
+                    space.maxX,
+                    space.minY,
+                    space.maxY
+                )
+            ) {
+                space.data.OutLine.forEach((item): void => {
+                    let minDisLine = SMathUtil.getMinDisLine(
+                        new SPoint(event.x, event.y),
+                        item
+                    );
+                    if (
+                        minDisLine &&
+                        minDisLine.MinDis < absorbLen &&
+                        minDisLine.MinDis < minPointDis
+                    ) {
+                        minPointDis = minDisLine.MinDis;
+                        Point = minDisLine.Point;
+                        Line = minDisLine.Line;
+                    }
+                });
+            }
+        });
+        return {
+            MinDis: minPointDis,
+            Point: Point,
+            Line: Line
+        };
+    } // Function absorbSpaceLine()
+}

+ 1 - 1
src/utils/graph/FloorScene.ts

@@ -268,7 +268,7 @@ export class FloorScene extends SGraphScene {
     /**
      * 清空业务空间
      */
-    removeAllZone(){
+    removeAllZone() {
         this.zoneList.forEach(t => {
             this.removeItem(t);
         })

+ 75 - 0
src/utils/graph/HighlightItem.ts

@@ -0,0 +1,75 @@
+import { ItemOrder } from "@persagy-web/big/lib";
+import { SColor, SLine, SPainter, SPoint, SRect } from "@persagy-web/draw/lib";
+import { SGraphItem, SGraphStyleItem } from "@persagy-web/graph/lib";
+
+/**
+ * 吸附时高亮对象
+ *
+ * @author  郝建龙
+ */
+export class HighlightItem extends SGraphStyleItem {
+    /** 对象与鼠标位置距离   */
+    distance: number = 0;
+    /** 对象类型   */
+    private type: number = 1;
+
+    /** 点对象数据-当吸附的为线时,此点为垂线与线段的交点   */
+    _point: SPoint = new SPoint();
+    get point(): SPoint {
+        return this._point;
+    } // Get point
+    set point(v: SPoint) {
+        this._point = v;
+        this.type = 1;
+        this.update();
+    } // Set point
+
+    /** 点对象数据   */
+    _line: SLine = new SLine();
+    get line(): SLine {
+        return this._line;
+    } // Get line
+    set line(v: SLine) {
+        this._line = v;
+        this.type = 2;
+        this.update();
+    } // Set line
+
+    /**
+     * 构造函数
+     *
+     * @param   parent  指向父对象
+     */
+    constructor(parent: SGraphItem | null) {
+        super(parent);
+        this.visible = false;
+        this.zOrder = ItemOrder.highLightOrder;
+        this.strokeColor = new SColor('#409EFF')
+        this.fillColor = new SColor('#ff8d00')
+    } // Constructor
+
+    /**
+     * Item对象边界区域
+     *
+     * @return	SRect
+     */
+    boundingRect(): SRect {
+        return new SRect(this.point.x, this.point.y, 10, 10);
+    } // Function boundingRect()
+
+    /**
+     * Item绘制操作
+     *
+     * @param   painter painter对象
+     */
+    onDraw(painter: SPainter): void {
+        if (this.type == 2) {
+            painter.pen.color = this.strokeColor;
+            painter.pen.lineWidth = painter.toPx(6);
+            painter.drawLine(this.line);
+        }
+        painter.pen.color = SColor.Transparent;
+        painter.brush.color = this.fillColor;
+        painter.drawCircle(this.point.x, this.point.y, painter.toPx(5));
+    } // Function onDraw()
+} // Class HighlightItem

+ 172 - 0
src/utils/graph/ShadeItem.ts

@@ -0,0 +1,172 @@
+import { SMouseEvent } from "@persagy-web/base/lib";
+import { ItemOrder } from "@persagy-web/big/lib";
+import { SMathUtil } from "@persagy-web/big/lib/utils/SMathUtil";
+import { SColor, SLineCapStyle, SPainter, SPoint, SPolygonUtil } from "@persagy-web/draw/lib";
+import { SGraphItem, SGraphStyleItem } from "@persagy-web/graph/lib";
+
+/**
+ * 遮罩item
+ *
+ * @author  郝建龙
+ */
+export class ShadeItem extends SGraphStyleItem {
+    /** 轮廓线坐标  */
+    outLine: SPoint[] = [];
+    /** 是否闭合    */
+    closeFlag = false;
+    /** 鼠标移动点  */
+    private lastPoint = new SPoint();
+
+    /**
+     * 构造函数
+     *
+     * @param parent    指向父对象
+     * @param data      遮罩起点数据
+     */
+    constructor(parent: SGraphItem | null, data: SPoint); // Constructor
+
+    /**
+     * 构造函数
+     *
+     * @param parent    指向父对象
+     * @param data      遮罩轮廓线数据
+     */
+    constructor(parent: SGraphItem | null, data: SPoint[]); // Constructor
+
+    /**
+     * 构造函数
+     *
+     * @param parent    指向父对象
+     * @param data      遮罩起点数据 | 遮罩轮廓线数据
+     */
+    constructor(parent: SGraphItem | null, data: SPoint[] | SPoint) {
+        super(parent);
+        if (data instanceof Array) {
+            this.outLine = data;
+            this.createMask();
+        } else {
+            this.outLine.push(data);
+            this.lastPoint = data;
+        }
+        this.zOrder = ItemOrder.shadeOrder;
+        this.fillColor = new SColor('#00000080')
+    } // Constructor
+
+    /**
+     * 鼠标按下事件
+     *
+     * @param	event         事件参数
+     * @return	boolean
+     */
+    onMouseDown(event: SMouseEvent): boolean {
+        if (!this.closeFlag && 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);
+            this.lastPoint.x = p.x;
+            this.lastPoint.y = p.y;
+            this.outLine.push(p);
+        }
+        this.update();
+        return true;
+    } // Function onMouseDown()
+
+    /**
+     * 鼠标移动事件
+     *
+     * @param	event         事件参数
+     * @return	boolean
+     */
+    onMouseMove(event: SMouseEvent): boolean {
+        if (!this.closeFlag) {
+            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         事件参数
+     * @return	boolean
+     */
+    onMouseUp(event: SMouseEvent): boolean {
+        return false;
+    } // Function onMouseUp()
+
+    /***
+     * 键盘按键弹起事件
+     *
+     * @param	event         事件参数
+     */
+    onKeyUp(event: KeyboardEvent): void {
+        if (event.keyCode == 13 && this.outLine.length >= 3) {
+            this.createMask();
+        }
+    } // Function onKeyUp()
+
+    /**
+     * 创建蒙版 
+     *
+     */
+    createMask(): void {
+        this.closeFlag = true;
+        this.releaseItem();
+        this.$emit('createSuc')
+        this.update();
+    } // Function createMask()
+
+    /**
+     * 判断点是否在区域内
+     *
+     * @param x
+     * @param y
+     */
+    contains(x: number, y: number): boolean {
+        let arr = this.outLine;
+        return SPolygonUtil.pointIn(x, y, arr);
+    } // Function contains()
+
+    /**
+     * Item绘制操作
+     *
+     * @param   painter       painter对象
+     */
+    onDraw(painter: SPainter): void {
+        painter.pen.lineCapStyle = SLineCapStyle.Square;
+        if (this.closeFlag) {
+            painter.pen.color = SColor.Transparent;
+            painter.brush.color = this.fillColor;
+            painter.drawPolygon(this.outLine);
+        } else {
+            painter.pen.color = new SColor("#ff0000");
+            painter.pen.lineWidth = painter.toPx(3);
+            painter.drawPolyline(this.outLine);
+            painter.drawLine(
+                this.outLine[this.outLine.length - 1],
+                this.lastPoint
+            );
+        }
+    } // Function onDraw()
+} // Class SceneMarkItem

+ 34 - 3
src/utils/graph/generate.ts

@@ -1,4 +1,6 @@
 import { SPoint } from "@persagy-web/draw/lib";
+// @ts-ignore
+import { intersect, polygon, segments, combine, selectUnion, selectDifference, selectDifferenceRev} from "polybooljs";
 
 export class generate {
     /**
@@ -106,7 +108,36 @@ export class generate {
         return null;
     }
 
-    /**
-     * 去除中间多于的点
-    */
+
+    static llll() {
+        const a = {
+            regions: [
+                [[0, 0], [0, 200], [200, 200], [200, 0]],
+                // [[150, 150], [250, 150], [250, 250], [150, 250]],
+            ],
+            inverted: false
+        }
+        const b = {
+            regions: [
+                [[150, 150], [250, 150], [250, 250], [150, 250]],
+            ],
+            inverted: false
+        }
+        const start = +new Date()
+        const sa = segments(a)
+        const sb = segments(b)
+        const comb = combine(sa, sb)
+        // const start = +new Date()
+        // const poly = segments(a)
+        // console.log(segments(a))
+        // const end = +new Date();
+        // console.log(end - start);
+        // console.log(polygon(poly));
+        console.log(comb);
+        const selecomb = selectDifference(comb)
+        console.log(selecomb)
+        console.log(polygon(selecomb))
+        const end = +new Date();
+        console.log(end - start);
+    }
 }

+ 11 - 7
src/views/maintain/space/components/spaceGraph.vue

@@ -68,7 +68,7 @@
 <script lang="ts">
 import { Vue, Component, Watch } from "vue-property-decorator";
 import { FloorView } from "@/utils/graph/FloorView";
-import { FloorScene } from "@/utils/graph/FloorScene";
+import { DivideFloorScene } from "@/utils/graph/DivideFloorScene";
 import canvasFun from "./canvasFun.vue";
 import {
     queryZone,
@@ -91,7 +91,7 @@ export default class spaceGraph extends Vue {
     canvasWidth = 800;
     canvasHeight = 800;
     view: FloorView | null = null;
-    scene: FloorScene | null = null;
+    scene: DivideFloorScene | null = null;
     canvasLoading = false;
     type = 1;
     config = {
@@ -130,9 +130,9 @@ export default class spaceGraph extends Vue {
         this.canvasLoading = true;
         if (floor.infos && floor.infos.floorMap) {
             this.floor = floor;
-            const url = this.mapBaseUrl + floor.infos.floorMap
+            const url = this.mapBaseUrl + floor.infos.floorMap;
             if (url == this.floorKey) {
-                this.init(2)
+                this.init(2);
             } else {
                 this.floorKey = this.mapBaseUrl + floor.infos.floorMap;
                 this.init(1);
@@ -152,6 +152,7 @@ export default class spaceGraph extends Vue {
         if (this.scene) {
             this.scene.selectContainer.clear();
             this.scene.initSpaceColor();
+            this.scene.clearCut();
             this.zoneDisable = true;
             this.scene.isZoneSelectable = true;
             this.scene.isSpaceSelectable = false;
@@ -180,7 +181,7 @@ export default class spaceGraph extends Vue {
     }
     // 获取底图
     getGraph(): void {
-        const scene = new FloorScene();
+        const scene = new DivideFloorScene();
         this.canvasLoading = true;
         this.clearGraphy();
         this.scene = null;
@@ -381,8 +382,11 @@ export default class spaceGraph extends Vue {
                 }
             } else {
                 this.scene?.initSpaceColor();
-                this.scene?.initZoneColor();
-                this.zoneDisable = true;
+                if (this.type == 3) {
+                } else {
+                    this.scene?.initZoneColor();
+                    this.zoneDisable = true;
+                }
             }
             data[0].forEach((t) => {
                 t.fillColor = ItemColor.selectColor;