Browse Source

feat: 优化数据处理

bill 1 year ago
parent
commit
8d8fb14c6a

+ 15 - 3
src/App.vue

@@ -1,15 +1,27 @@
 <template>
-  <ElButton @click="mound = !mound">销毁测试</ElButton>
+  <div id="right-pano">
+    <ElButton @click="mound = !mound">销毁测试</ElButton>
+  </div>
   <QueryBoard :width="width" :height="height" v-if="mound" />
 </template>
 
 <script setup lang="ts">
 import { ref } from "vue";
 import { ElButton } from "element-plus";
-import QueryBoard from "./app/4dmap/example/index.vue";
-// import QueryBoard from "./app/liantong/example/index.vue";
+// import QueryBoard from "./app/4dmap/example/index.vue";
+import QueryBoard from "./app/liantong/example/index.vue";
 
 const mound = ref(true);
 const width = window.innerWidth;
 const height = window.innerHeight;
 </script>
+
+<style>
+#right-pano {
+  position: absolute;
+  right: 0;
+  top: 0;
+  max-width: 200px;
+  z-index: 1;
+}
+</style>

+ 35 - 19
src/app/4dmap/index.ts

@@ -1,5 +1,10 @@
 import { Polygons } from "./polygons";
-import { register, BoundQueryPlugin, setGenerateStartId } from "../../board";
+import {
+  register,
+  BoundQueryPlugin,
+  setGenerateStartId,
+  inRevise,
+} from "../../board";
 import { PolygonsAttrib } from "./type";
 import { Map } from "ol";
 import { boundingExtent } from "ol/extent";
@@ -9,8 +14,9 @@ const boundJoinMap = (
   mountDOM?: HTMLDivElement,
   map?: Map
 ) => {
+  let mapView = map?.getView();
   const getMapBound = () => {
-    return map.getView().calculateExtent(map.getSize());
+    return mapView.calculateExtent(map.getSize());
   };
 
   const setMapBound = (bound: number[]) => {
@@ -18,26 +24,32 @@ const boundJoinMap = (
       [bound[0], bound[1]],
       [bound[2], bound[3]],
     ]);
-    map.getView().fit(extent, {
+    mapView.fit(extent, {
       size: map.getSize(),
       padding: [0, 0, 0, 0], // 根据需要调整边距
-      maxZoom: 19.5, // 防止过度放大
     });
   };
 
   const setBoardBound = () => {
     if (mountDOM && map) {
       const bound = getMapBound();
-      boundQuery.setSize(mountDOM.offsetWidth, mountDOM.offsetHeight);
-      boundQuery.setBound([bound[0], bound[3], bound[2], bound[1]]);
+      if (!boundQuery.bound || inRevise(boundQuery.bound, bound)) {
+        boundQuery.setSize(mountDOM.offsetWidth, mountDOM.offsetHeight);
+        boundQuery.setBound([bound[0], bound[3], bound[2], bound[1]]);
+      }
     }
   };
 
   const setMap = (bindMap: Map) => {
     if (map) {
+      mapView.removeEventListener("change:center", setBoardBound);
+      mapView.removeEventListener("change:resolution", setBoardBound);
       map.removeEventListener("moveend", setBoardBound);
     }
-    bindMap.addEventListener("moveend", setBoardBound);
+    mapView = bindMap.getView();
+    mapView.addEventListener("change:center", setBoardBound);
+    mapView.addEventListener("change:resolution", setBoardBound);
+    map.addEventListener("moveend", setBoardBound);
     map = bindMap;
     setBoardBound();
   };
@@ -53,11 +65,14 @@ const boundJoinMap = (
 
   return {
     setMap,
+    setBoardBound,
     setMountDom(dom: HTMLDivElement) {
       mountDOM = dom;
       setBoardBound();
     },
     destory() {
+      mapView.removeEventListener("change:center", setBoardBound);
+      mapView.removeEventListener("change:resolution", setBoardBound);
       map.removeEventListener("moveend", setBoardBound);
     },
   };
@@ -81,21 +96,20 @@ export const createBoard = (
   const board = initBoard(props.dom, { polygons: data }, false);
   const mapJoin = boundJoinMap(board.bound, props.dom, props.map);
 
-  board.tree.bus.on("active", (entity) => {
-    console.log(entity);
-  });
+  const setProps = (props: { dom?: HTMLDivElement; map?: Map } = {}) => {
+    if (props.dom) {
+      board.mount(props.dom);
+      mapJoin.setMountDom(props.dom);
+    }
+    if (props.map) {
+      mapJoin.setMap(props.map);
+    }
+  };
+  setProps(props);
 
   return {
     raw: board,
-    setProps(props: { dom?: HTMLDivElement; map?: Map }) {
-      if (props.dom) {
-        board.mount(props.dom);
-        mapJoin.setMountDom(props.dom);
-      }
-      if (props.map) {
-        mapJoin.setMap(props.map);
-      }
-    },
+    setProps,
     getData() {
       return board.getData().polygons[0];
     },
@@ -118,3 +132,5 @@ export const createBoard = (
 export * from "../../board";
 export * from "./polygons";
 export * from "./type";
+export * from "./path";
+export * from "./point";

+ 8 - 4
src/app/4dmap/path.ts

@@ -22,11 +22,11 @@ const polygonActShapeFactory = (attrib, tree) => {
       act.closeLine.common();
     },
     hover() {
-      path.fill("rgba(0, 0, 0, 0.3)");
+      path.fill("rgba(230, 162, 60, 0.3)");
       act.closeLine.hover();
     },
     active() {
-      path.fill("rgba(0, 0, 0, 0.3)");
+      path.fill("rgba(64, 158, 255, 0.3)");
       act.closeLine.active();
       if (!polygons.status.newModel) {
         polygons.bus.emit("clickPolygon", attrib);
@@ -50,8 +50,12 @@ export class PoPath extends WholeLinePolygon<WholeLinePolygonAttrib, Group> {
       super.initReactive(),
       watchEffect(
         () => {
-          if (polygons.status.editPolygonId === this.attrib.id) {
-            this.bus.emit("statusChange", { active: true });
+          if (polygons.status.editPolygonId) {
+            if (polygons.status.editPolygonId === this.attrib.id) {
+              this.bus.emit("statusChange", { active: true });
+            } else {
+              this.bus.emit("statusChange", { common: true });
+            }
           } else if (polygons.status.lightPolygonId === this.attrib.id) {
             this.bus.emit("statusChange", { hover: true });
           } else {

+ 26 - 35
src/app/4dmap/point.ts

@@ -15,9 +15,9 @@ import { Circle } from "konva/lib/shapes/Circle";
 import { Polygons } from "./polygons";
 import { point } from "../../board/packages/whole-line/style";
 import { Label, Tag } from "konva/lib/shapes/Label";
-import { watch, watchEffect } from "vue";
+import { watch } from "vue";
 
-const pointActShapeFactory = (attrib: PolygonsPointAttrib, tree: Point) => {
+const pointActShapeFactory = (attrib: PolygonsPointAttrib, tree: PoPoint) => {
   const polygons = tree.parent as unknown as Polygons;
   const size = { width: 43, height: 44 };
   const out = new Path({
@@ -72,7 +72,14 @@ const pointActShapeFactory = (attrib: PolygonsPointAttrib, tree: Point) => {
   });
 
   rectGroup.add(index, label, rect);
-
+  const text = new Text({
+    name: "text",
+    text: attrib.title || `P${attrib.id}`,
+    fontFamily: "Calibri",
+    fontSize: 10,
+    padding: 5,
+    fill: "#000",
+  });
   label.add(
     new Tag({
       name: "tag",
@@ -87,14 +94,7 @@ const pointActShapeFactory = (attrib: PolygonsPointAttrib, tree: Point) => {
       shadowOffsetY: 10,
       shadowOpacity: 0.5,
     }),
-    new Text({
-      name: "text",
-      text: attrib.title || `P${attrib.id}`,
-      fontFamily: "Calibri",
-      fontSize: 10,
-      padding: 5,
-      fill: "#000",
-    })
+    text
   );
 
   const offsetGroup = new Group();
@@ -121,6 +121,7 @@ const pointActShapeFactory = (attrib: PolygonsPointAttrib, tree: Point) => {
       group.scale({ x: width, y: height });
       group.x(data[0]);
       group.y(data[1]);
+      text.text(attrib.title || `P${attrib.id}`);
 
       if (polygons.status.activePointId === attrib.id) {
         label.visible(true);
@@ -154,7 +155,7 @@ const pointActShapeFactory = (attrib: PolygonsPointAttrib, tree: Point) => {
   return result;
 };
 
-export class Point extends WholeLinePoint<PolygonsPointAttrib, Group> {
+export class PoPoint extends WholeLinePoint<PolygonsPointAttrib, Group> {
   actShape: CustomizeShape<number[], Group, { setNdx: (ndx: number) => void }> =
     null;
 
@@ -177,21 +178,13 @@ export class Point extends WholeLinePoint<PolygonsPointAttrib, Group> {
   }
 
   protected initReactive() {
-    const polygons = this.parent as unknown as Polygons;
     return mergeFuns(
       super.initReactive(),
-      watchEffect(() => {
-        if (polygons.status.editPolygonId === this.attrib.id) {
-          this.bus.emit("statusChange", { active: true });
-        } else {
-          this.bus.emit("statusChange", { active: false });
-        }
-      }),
       watch(
         () => this.editPolygonNdx,
         (endx, _, onCleanup) => {
-          if (!~endx) {
-            onCleanup(() => {});
+          if (!~endx || this.attrib.rtk) {
+            return onCleanup(() => {});
           }
           const anchor = this.shape.findOne<Group>(".anchor-move");
 
@@ -206,19 +199,17 @@ export class Point extends WholeLinePoint<PolygonsPointAttrib, Group> {
             clearCursor = null;
           });
 
-          if (!this.attrib.rtk) {
-            openEntityDrag(this, {
-              readyHandler: (attrib) => {
-                return [attrib.x, attrib.y];
-              },
-              moveHandler: (pointAttrib, move) => {
-                if (~this.editPolygonNdx) {
-                  pointAttrib.x = move[0];
-                  pointAttrib.y = move[1];
-                }
-              },
-            });
-          }
+          openEntityDrag(this, {
+            readyHandler: (attrib) => {
+              return [attrib.x, attrib.y];
+            },
+            moveHandler: (pointAttrib, move) => {
+              if (~this.editPolygonNdx) {
+                pointAttrib.x = move[0];
+                pointAttrib.y = move[1];
+              }
+            },
+          });
 
           onCleanup(() => {
             anchor.off("mouseenter.anchor mouseleave.anchor");

+ 3 - 6
src/app/4dmap/polygons.ts

@@ -17,7 +17,7 @@ import {
   shapeParentsEq,
 } from "../../board";
 import { reactive } from "vue";
-import { Point } from "./point";
+import { PoPoint } from "./point";
 import { PoPath } from "./path";
 import { lineShapeFactory } from "../../board/packages/whole-line/style";
 
@@ -122,7 +122,7 @@ export class Polygons extends WholeLine<
 
   initIncFactory() {
     super.initIncFactory();
-    this.incPointsFactory = incEntitysFactoryGenerate(Point, this);
+    this.incPointsFactory = incEntitysFactoryGenerate(PoPoint, this);
     this.incLinesFactory = incEntitysFactoryGenerate(
       WholeLineLine,
       this,
@@ -133,14 +133,11 @@ export class Polygons extends WholeLine<
     );
     this.incPolygonFactory = incEntitysFactoryGenerate(PoPath, this, (py) => {
       py.setConfig(this.attrib);
-    });
+    }) as any;
   }
 
   private endEditPolygon: () => void;
   editPolygon(polygonId?: string) {
-    if (this.endEditPolygon) {
-      console.log(this.endEditPolygon);
-    }
     this.endEditPolygon && this.endEditPolygon();
     this.status.newModel = !polygonId;
     this.endEditPolygon = penWholeLinePoygonsEditWithHelperShapesMouse(

+ 1 - 1
src/app/4dmap/type.ts

@@ -12,6 +12,6 @@ export type PolygonsLineAttrib = WholeLineLineAttrib;
 
 export type PolygonsAttrib = {
   lines: PolygonsLineAttrib[];
-  polygons: WholeLinePolygonAttrib[];
+  polygons: (WholeLinePolygonAttrib & { name: string })[];
   points: PolygonsPointAttrib[];
 };

+ 5 - 4
src/app/liantong/example/index.vue

@@ -1,5 +1,5 @@
 <template>
-  <div>
+  <Teleport to="#right-pano">
     <ElButton @click="board.clear()"> 清除 </ElButton>
     <ElButton :disabled="!board.history.state.hasUndo" @click="board.history.undo()">
       撤销
@@ -24,8 +24,8 @@
     </template>
 
     <ElButton @click="board.showPois()"> 显示图例 </ElButton>
-    <ElButton @click="board.hidenPois()"> 隐藏图例 </ElButton>
-  </div>
+    <ElButton @click="board.hidenPois()"> 隐藏图例 </ElButton></Teleport
+  >
   <div
     class="board-layout"
     :style="{ width: width + 'px', height: height + 'px' }"
@@ -48,7 +48,8 @@ withDefaults(defineProps<{ width?: number; height?: number; pixelRation?: number
 type Board = ReturnType<typeof createBoard>;
 
 const board = createBoard();
-board.bound.setBound([-9.0754444, -5.6740986, 9.0754444, 5.6740986]);
+board.bound.setRetainScale(true);
+board.bound.setBound([-9.0754444, -5.6740986, 9.0754444, 5.6740986], [0, 0]);
 
 setTimeout(() => {
   board.setData(storeData);

+ 4 - 9
src/app/liantong/index.ts

@@ -118,23 +118,18 @@ export const createBoard = (
     showPois() {
       if (!board.tree.entrys.pois) return;
       const pois = board.tree.entrys.pois as Entity[];
-      pois.forEach((poi) => {
-        poi.shape.show();
-      });
+      pois.forEach((poi) => poi.visible(true));
     },
     hidenPois() {
       if (!board.tree.entrys.pois) return;
       const pois = board.tree.entrys.pois as Entity[];
-      pois.forEach((poi) => {
-        poi.shape.hide();
-      });
+      pois.forEach((poi) => poi.visible(false));
     },
     addPoi(type: string) {
       if (!pois()) {
         const data = board.getData();
-        board.setData({ ...data, pois: [] });
+        data.pois = [];
       }
-      console.log(pois());
       board.tree.bus.emit("dataChangeBefore");
       const { promise, interrupt } = addEntityAttrib(board.tree, (pos) => {
         const attrib = {
@@ -143,8 +138,8 @@ export const createBoard = (
           y: pos[1],
           type,
         };
-        console.log(attrib);
         pois().push(attrib);
+        console.log(board.getData() === board.tree.attrib.data);
       });
       promise.finally(() => {
         board.tree.bus.emit("dataChangeAfter");

+ 0 - 1
src/assets/vue.svg

@@ -1 +0,0 @@
-<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="iconify iconify--logos" width="37.07" height="36" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 198"><path fill="#41B883" d="M204.8 0H256L128 220.8L0 0h97.92L128 51.2L157.44 0h47.36Z"></path><path fill="#41B883" d="m0 0l128 220.8L256 0h-51.2L128 132.48L50.56 0H0Z"></path><path fill="#35495E" d="M50.56 0L128 133.12L204.8 0h-47.36L128 51.2L97.92 0H50.56Z"></path></svg>

+ 1 - 15
src/board/packages/container.ts

@@ -1,4 +1,3 @@
-import { watch } from "vue";
 import { Attrib, ShapeType } from "../type";
 import { Layer } from "konva/lib/Layer";
 import { Entity, EntityEvent, EntityProps, EntityType } from "./entity";
@@ -159,20 +158,7 @@ export class Container<
   }
 
   initReactive() {
-    return watch(
-      () => {
-        const result = {} as { [key in T]: string | string[] };
-        for (const key in this.attrib.data as any) {
-          const child = this.attrib.data[key];
-          result[key] = Array.isArray(child)
-            ? child.map(({ id }) => id)
-            : child.id;
-        }
-        return result;
-      },
-      this.diffRedraw.bind(this),
-      { immediate: true, flush: "sync" }
-    );
+    return super.initReactive("sync");
   }
 
   // 临时绘制

+ 28 - 9
src/board/packages/entity.ts

@@ -5,7 +5,7 @@ import { Group } from "konva/lib/Group";
 import { Layer } from "konva/lib/Layer";
 import { Stage } from "konva/lib/Stage";
 import { depPartialUpdate } from "../shared/util";
-import { reactive, watch, watchEffect } from "vue";
+import { reactive, toRaw, watch, watchEffect } from "vue";
 import {
   DragHandlers,
   openShapeDrag,
@@ -96,16 +96,23 @@ export abstract class Entity<
   }
 
   setAttrib(newAttrib: Partial<T>) {
-    this.attrib = depPartialUpdate(
-      { ...newAttrib, id: this.attrib.id } as T,
-      this.attrib
-    );
-    this.props.reactive || this.diffRedraw();
-    console.error("setAttrib");
+    newAttrib.id = this.attrib.id;
+    if (this.props.reactive) {
+      if (toRaw(newAttrib) !== toRaw(this.attrib)) {
+        this.attrib = (
+          this.props.reactive ? reactive(newAttrib) : newAttrib
+        ) as T;
+        this.initReactive();
+      }
+    } else {
+      this.attrib = newAttrib as T;
+      this.diffRedraw();
+    }
   }
 
   private destoryReactive: () => void;
-  protected initReactive(flush: "pre" | "post" | "sync" = "pre") {
+  private flush: "pre" | "post" | "sync" = "pre";
+  protected initReactive(flush = this.flush) {
     this.destoryReactive && this.destoryReactive();
     let isStop = false;
     const stop = watchEffect(
@@ -114,6 +121,7 @@ export abstract class Entity<
       },
       { flush }
     );
+    this.flush = flush;
     return () => {
       isStop = true;
       stop();
@@ -277,13 +285,20 @@ export abstract class Entity<
     this.mouseActDestory && this.mouseActDestory();
     this.mouseActDestory = null;
   }
+  visible(visibled: boolean) {
+    this.shape.visible(visibled);
+  }
 
   destory() {
+    while (this.children.length) {
+      this.children[0].destory();
+    }
+
     this.setParent(null);
     this.destoryReactive && this.destoryReactive();
     this.disableDrag();
     this.disableActive();
-    this.disableActive();
+    this.disableMouseAct();
 
     if (DEV) {
       console.log(this.name, "destory");
@@ -293,6 +308,10 @@ export abstract class Entity<
     } else {
       this.shape.destroy();
     }
+    if (this.parent) {
+      const ndx = this.parent.children.indexOf(this);
+      ~ndx && this.parent.children.splice(ndx, 1);
+    }
     this.bus.emit("destroyed");
     this.bus.off("*");
   }

+ 1 - 1
src/board/packages/whole-line/editable/edit-whole-line.ts

@@ -120,7 +120,6 @@ export class EditWholeLine<
             }
           },
           quitHandler: () => {
-            this.container.bus.emit("dataChangeAfter");
             this.endCreatePolygon = null;
             prePolygonIds.forEach((pid) => {
               const polygonAttrib = getWholeLinePolygonRaw(this.attrib, pid);
@@ -135,6 +134,7 @@ export class EditWholeLine<
             resolve(interrupt ? "cancel" : "submit");
             enableMouse();
             this.container.constant.unuse();
+            this.container.bus.emit("dataChangeAfter");
           },
         },
         this.shape

+ 11 - 7
src/board/packages/whole-line/service/whole-line-helper.ts

@@ -83,6 +83,7 @@ export const penWholeLinePoygonsEditWithHelperMouse = <
   };
 
   let prevOffset: { x: number; y: number };
+  let continuousTimeout;
   const clickHandler = (evt: KonvaEventObject<any>) => {
     const [offset] = getRealAbsoluteSize(stage, [4, 4], true);
     if (
@@ -92,13 +93,15 @@ export const penWholeLinePoygonsEditWithHelperMouse = <
     ) {
       return;
     } else {
-      const { isClose, change } = edit.continuous(evt);
-      syncHelper();
-      if (isClose && props.closeAutoQuit) {
-        leaveEditMode();
-      }
-      props.onChange && props.onChange(change);
-      prevOffset = null;
+      continuousTimeout = setTimeout(() => {
+        const { isClose, change } = edit.continuous(evt);
+        syncHelper();
+        if (isClose && props.closeAutoQuit) {
+          leaveEditMode();
+        }
+        props.onChange && props.onChange(change);
+        prevOffset = null;
+      });
     }
   };
 
@@ -138,6 +141,7 @@ export const penWholeLinePoygonsEditWithHelperMouse = <
   };
 
   const quitHandler = (ev: Event) => {
+    clearTimeout(continuousTimeout);
     if (ev instanceof KeyboardEvent) {
       ev.key === "Escape" && leaveEditMode();
     } else {

+ 0 - 1
src/board/packages/whole-line/style.ts

@@ -58,7 +58,6 @@ export const line = {
   hitStrokeWidth: 20,
   stroke: "rgba(230, 162, 60, 1)",
   zIndex: 1,
-
   activeStroke: "rgba(64, 158, 255, 1)",
 };
 

+ 17 - 6
src/board/plugins/camera-plugin.ts

@@ -9,9 +9,11 @@ export type CameraQueryPluginProps = {
   bound?: number[];
   padding?: number | number[];
   size?: number[];
+  retainScale?: boolean;
 };
 
 export class CameraQueryPlugin {
+  retainScale: boolean;
   bound: number[];
   padding: number[];
   tree: Container;
@@ -25,6 +27,7 @@ export class CameraQueryPlugin {
     this.props.move = props.move || false;
     this.props.wheel = props.wheel || false;
     this.cameraMat = new Matrix4();
+    this.retainScale = props.retainScale || false;
 
     if (props.size) {
       this.setSize(props.size[0], props.size[1]);
@@ -163,7 +166,7 @@ export class CameraQueryPlugin {
   }
 
   realBound: number[];
-  setBound(bound: number[], padding?: number | number[], retainScale = false) {
+  setBound(bound: number[], padding?: number | number[]) {
     padding = !Array.isArray(padding) ? [padding || 0, padding || 0] : padding;
     if (padding.length === 1) {
       padding.push(padding[0]);
@@ -186,7 +189,7 @@ export class CameraQueryPlugin {
     // 计算缩放比例
     let scaleX = effectiveWidth / realWidth;
     let scaleY = effectiveHeight / realHeight;
-    if (retainScale) {
+    if (this.retainScale) {
       const scale = Math.min(scaleX, scaleY); // 选择较小的比例以保持内容比例
       scaleX = scale;
       scaleY = scale;
@@ -207,14 +210,23 @@ export class CameraQueryPlugin {
     this.update();
   }
 
-  setSize(width: number, height: number) {
-    this.tree.stage.width(width);
-    this.tree.stage.height(height);
+  private updateSelfBound() {
     if (this.bound) {
       this.setBound(this.bound, this.padding);
     }
   }
 
+  setRetainScale(retainScale: boolean) {
+    this.retainScale = retainScale;
+    this.updateSelfBound();
+  }
+
+  setSize(width: number, height: number) {
+    this.tree.stage.width(width);
+    this.tree.stage.height(height);
+    this.updateSelfBound();
+  }
+
   setTree(tree: Container) {
     this.tree = tree;
     if (this.props.move) {
@@ -226,7 +238,6 @@ export class CameraQueryPlugin {
   }
 
   update() {
-    console.log(this.clipMat.clone().multiply(this.cameraMat));
     this.tree.updateViewMat(this.clipMat.clone().multiply(this.cameraMat));
   }
 }

+ 0 - 1
src/board/shared/act.ts

@@ -67,7 +67,6 @@ export const pathsToActShape = (props: PathsToActShapeProps, test = false) => {
     },
     shape: group,
     setData(data) {
-      console.log("set", data);
       group.position(data);
       props.fixed && setStyle();
     },

+ 8 - 9
src/board/shared/entity-utils.ts

@@ -7,7 +7,7 @@ import { getTouchOffset } from "./act";
 import { createLineByDire, getLineProjection } from "./math";
 import { inRevise } from "./public";
 import { disableMouse, enableMouse } from "./shape-mose";
-import { generateId, getChangePart } from "./util";
+import { generateId, getChangeAllPoart, getChangePart } from "./util";
 
 const getExtendsProps = (parent: Entity<any, any>) => {
   return parent
@@ -90,20 +90,19 @@ export const incEntitysFactoryGenerate = <
   return (attribsRaw: T | T[]) => {
     const attribs = Array.isArray(attribsRaw) ? attribsRaw : [attribsRaw];
 
-    const { addPort, delPort } = getChangePart(attribs, oldAttribs);
-    const changePort = [];
+    const { addPort, delPort, changePort } = getChangeAllPoart(
+      attribs,
+      oldAttribs
+    );
 
-    const dels = delPort.map((d) => destory(d.id));
-    const adds = addPort.map((d) => add(findAttrib(attribs, d.id)));
+    const dels = delPort.map(destory);
+    const adds = addPort.map((id) => add(findAttrib(attribs, id)));
 
     const upds = changePort.map((id) => {
       const newAttrib = findAttrib(attribs, id);
-      if (inRevise(newAttrib, cache[id].attrib)) {
-        cache[id].setAttrib(findAttrib(attribs, id));
-      }
+      cache[id].setAttrib(newAttrib);
       return cache[id];
     });
-
     oldAttribs = [...attribs];
     return {
       adds,

+ 11 - 2
src/board/shared/shape-mose.ts

@@ -21,7 +21,7 @@ export const getActiveKey = (
   status: Partial<ShapeStylesStatus>,
   excludes: string[] = []
 ) => {
-  const apis = ["draging", "active", "hover"] as const;
+  const apis = ["draging", "active", "hover", "common"] as const;
   return apis.find((api) => status[api] && !excludes.includes(api));
 };
 
@@ -53,6 +53,7 @@ export const openShapeMouseStyles = <T extends Shape | Group>(
     hover: false,
     draging: false,
     active: false,
+    common: false,
   };
   let prevApi = "common";
 
@@ -91,9 +92,17 @@ export const openShapeMouseStyles = <T extends Shape | Group>(
     const e = `click.${namespace}${shape.id()} touchend.${namespace}${shape.id()}`;
     let count = 3;
     let stage;
+    let tip = false;
     const interval = setInterval(() => {
       if (!(stage = shape.getStage())) {
-        if (--count < 0) console.error("可能发生资源泄露");
+        if (count < -5) {
+          clearInterval(interval);
+          console.log(shape.name(), shape.id());
+        }
+        if (--count < 0) {
+          tip && console.error("可能发生资源泄露");
+          tip = true;
+        }
         return;
       }
       clearInterval(interval);

+ 1 - 0
src/board/type.ts

@@ -19,6 +19,7 @@ export type ShapeStylesStatus = {
   draging: boolean;
   hover: boolean;
   active: boolean;
+  common: boolean;
 };
 export type ShapeStyles = {
   common: (ev?: KonvaEventObject<any>) => void;

+ 0 - 11
src/util/index.ts

@@ -1,11 +0,0 @@
-export const mergeFuns = (...fns: (() => void)[] | (() => void)[][]) => {
-  return () => {
-    fns.forEach((fn) => {
-      if (Array.isArray(fn)) {
-        fn.forEach((f) => f());
-      } else {
-        fn();
-      }
-    });
-  };
-};