Forráskód Böngészése

Merge branch 'master' of http://192.168.0.115:3000/bill/drawing-board

bill 1 éve
szülő
commit
606b5d5f85

+ 113 - 0
src/app/4dmap/index.ts

@@ -0,0 +1,113 @@
+import { Polygons } from "./polygons";
+import { register, BoundQueryPlugin } from "../../board";
+import { PolygonsAttrib } from "./type";
+import { Map } from "ol";
+import { boundingExtent } from "ol/extent";
+
+const boundJoinMap = (
+  boundQuery: BoundQueryPlugin,
+  mountDOM?: HTMLDivElement,
+  map?: Map
+) => {
+  const getMapBound = () => {
+    return map.getView().calculateExtent(map.getSize());
+  };
+
+  const setMapBound = (bound: number[]) => {
+    const extent = boundingExtent([
+      [bound[0], bound[1]],
+      [bound[2], bound[3]],
+    ]);
+    map.getView().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]]);
+    }
+  };
+
+  const setMap = (bindMap: Map) => {
+    if (map) {
+      map.removeEventListener("moveend", setBoardBound);
+    }
+    bindMap.addEventListener("moveend", setBoardBound);
+    map = bindMap;
+    setBoardBound();
+  };
+
+  boundQuery.enableMove((newBound) => {
+    map && setMapBound(newBound);
+    return true;
+  });
+  boundQuery.enableWheel((newBound) => {
+    map && setMapBound(newBound);
+    return true;
+  });
+
+  return {
+    setMap,
+    setMountDom(dom: HTMLDivElement) {
+      mountDOM = dom;
+      setBoardBound();
+    },
+    destory() {
+      map.removeEventListener("moveend", setBoardBound);
+    },
+  };
+};
+
+const initBoard = register(
+  { polygons: Polygons },
+  { bound: new BoundQueryPlugin() }
+);
+
+export const createBoard = (
+  props: {
+    dom?: HTMLDivElement;
+    store?: PolygonsAttrib & { id: string };
+    map?: Map;
+  } = {}
+) => {
+  const data = props.store || { id: "0", points: [], polygons: [], lines: [] };
+  const board = initBoard(props.dom, { polygons: data }, false);
+  const mapJoin = boundJoinMap(board.bound, props.dom, props.map);
+
+  return {
+    setProps(props: { dom?: HTMLDivElement; map?: Map }) {
+      if (props.dom) {
+        board.mount(props.dom);
+        mapJoin.setMountDom(props.dom);
+      }
+      if (props.map) {
+        mapJoin.setMap(props.map);
+      }
+    },
+    getData() {
+      return board.getData().polygons;
+    },
+    setData(polygons: PolygonsAttrib & { id: string }) {
+      board.setData({ polygons });
+    },
+    destory() {
+      mapJoin.destory();
+      board.destory();
+    },
+    get polygon() {
+      return board.tree.children[0] as Polygons;
+    },
+    getPixelFromCoordinate(point: number[]) {
+      return board.tree.getPixelFromStage(point);
+    },
+  };
+};
+
+export * from "../../board";
+export * from "./polygons";
+export * from "./type";

+ 291 - 0
src/app/4dmap/polygons.ts

@@ -0,0 +1,291 @@
+import { PolygonsAttrib, PolygonsPointAttrib } from "./type";
+import {
+  incEntitysFactoryGenerate,
+  Attrib,
+  wholeLineStyle,
+  getRealAbsoluteSize,
+  PenEditWholeLine,
+  WholeLinePoint,
+  getWholeLinePolygonPoints,
+  shapeParentsEq,
+  openEntityDrag,
+  WholeLineInc,
+} from "../../board";
+import { Group } from "konva/lib/Group";
+import { Path } from "konva/lib/shapes/Path";
+import { Circle } from "konva/lib/shapes/Circle";
+import { Label, Tag } from "konva/lib/shapes/Label";
+import { Text } from "konva/lib/shapes/Text";
+import { ref } from "vue";
+import mitt from "mitt";
+import { point } from "../../board/packages/whole-line/style";
+
+// 加点
+const getPolygonPoint = (position: number[]) => {
+  const pointAttrib = {
+    rtk: false,
+    title: "",
+    x: position[0],
+    y: position[1],
+  };
+  return pointAttrib;
+};
+
+const pointActShapeFactory = (attrib: PolygonsPointAttrib, tree: any) => {
+  const polygons = tree.parent as Polygons;
+  const size = { width: 43, height: 44 };
+  const out = new Path({
+    data: `M22 44C32.6667 33.891 38 25.891 38 20C38 11.1634 30.8366 4 22 4C13.1634 4 6 11.1634 6 20C6 25.891 11.3333 33.891 22 44Z`,
+    strokeScaleEnabled: true,
+    stroke: "#ffffff",
+    strokeWidth: 1,
+  });
+  const inner = new Path({
+    fill: "#fff",
+    data: `M22 30C27.5228 30 32 25.5228 32 20C32 14.4772 27.5228 10 22 10C16.4772 10 12 14.4772 12 20C12 25.5228 16.4772 30 22 30Z`,
+  });
+  const rect = new Circle({
+    name: "anchor-move",
+    radius: Math.min(size.width, size.height) / 2,
+    fill: "rgba(0, 0, 0, 0)",
+    offset: { x: -size.width / 2, y: -size.height / 2 },
+  });
+  const wlp = wholeLineStyle.pointShapeFactory();
+  point.radius = 5;
+
+  point.hitStrokeWidth = point.strokeWidth = 4;
+  wlp.shape.name("anchor-point");
+
+  const index = new Text({
+    name: "text",
+    text: `1`,
+    fontFamily: "Calibri",
+    fontSize: 12,
+    padding: 5,
+    offsetY: -8,
+    fill: "#000",
+  });
+
+  const label = new Label({
+    visible: false,
+    opacity: 0.75,
+    name: "label",
+    offsetX: -size.width / 2,
+    offsetY: -6,
+  });
+
+  label.add(
+    new Tag({
+      name: "tag",
+      fill: "rgba(255, 255, 255, 0.8)",
+      pointerDirection: "down",
+      pointerWidth: 5,
+      pointerHeight: 5,
+      lineJoin: "round",
+      shadowColor: "black",
+      shadowBlur: 10,
+      shadowOffsetX: 10,
+      shadowOffsetY: 10,
+      shadowOpacity: 0.5,
+    }),
+    new Text({
+      name: "text",
+      text: attrib.title || `P${attrib.id}`,
+      fontFamily: "Calibri",
+      fontSize: 10,
+      padding: 5,
+      fill: "#000",
+    })
+  );
+
+  const offsetGroup = new Group();
+  offsetGroup.add(out, inner, rect, label, index);
+  offsetGroup.x(-size.width / 2);
+  offsetGroup.y(-size.height);
+
+  const group = new Group();
+  group.add(offsetGroup, wlp.shape);
+
+  const activeNdx = () => {
+    if (polygons.editPolygonId.value) {
+      const points = getWholeLinePolygonPoints(
+        polygons.attrib,
+        polygons.editPolygonId.value
+      ).map(({ id }) => id);
+      const ndx = points.indexOf(attrib.id);
+      return ndx;
+    }
+    return -1;
+  };
+
+  const setStyle = () => {
+    let [width, height] = getRealAbsoluteSize(group, [1, 1]);
+    group.scale({ x: width, y: height });
+    const ndx = activeNdx();
+    if (~ndx) {
+      index.text((ndx + 1).toString()).visible(true);
+      index.offsetX(-rect.width() / 2 + index.width() / 2);
+    } else {
+      index.visible(false);
+    }
+  };
+
+  const commonStyle = () => {
+    out.fill(attrib.rtk ? "rgba(230, 162, 60, 1)" : "#409EFF");
+    label.visible(false);
+    wlp.common();
+  };
+
+  const result = {
+    shape: group,
+    common: commonStyle,
+    hover: () => {
+      label.visible(true);
+    },
+    setData(data: number[]) {
+      setStyle();
+      group.x(data[0]);
+      group.y(data[1]);
+
+      label.visible(polygons.activePointId.value === attrib.id);
+    },
+    draging() {
+      if (polygons.editPolygonId.value && !attrib.rtk) {
+        out.fill("#e0403c");
+      }
+    },
+    active() {
+      polygons.activePointId.value = attrib.id;
+      polygons.bus.emit("clickPoint", attrib);
+    },
+  };
+
+  return result;
+};
+
+export class Polygons extends PenEditWholeLine<PolygonsAttrib & Attrib> {
+  bus = mitt<{ clickPoint: PolygonsPointAttrib; penEndHandler: void }>();
+  activePointId = ref<string>();
+
+  dragAttach(inc: WholeLineInc<PolygonsAttrib & Attrib>) {
+    inc.pointEntityInc.adds.forEach((point) => {
+      openEntityDrag(point, {
+        readyHandler: (attrib) => {
+          return [attrib.x, attrib.y];
+        },
+        moveHandler: (pointAttrib, move) => {
+          if (this.editPolygonId.value && !pointAttrib.rtk) {
+            pointAttrib.x = move[0];
+            pointAttrib.y = move[1];
+          }
+        },
+      });
+      point.enableMouseAct(point.actShape);
+    });
+
+    inc.lineEntityInc.adds.forEach((line) => {
+      line.enableMouseAct(line.actShape);
+    });
+
+    inc.polygonEntityInc.adds.forEach((py) => {
+      py.enableMouseAct(py.actShape);
+    });
+  }
+
+  removePolygon(polygonId: string) {
+    const ndx = this.attrib.polygons.findIndex(({ id }) => id === polygonId);
+    if (!~ndx) {
+      return;
+    }
+    const polygonLines = this.attrib.polygons[ndx].lineIds;
+    let joinPointIds: string[] = [];
+
+    while (polygonLines.length) {
+      const ndx = this.attrib.lines.findIndex(
+        ({ id }) => id === polygonLines[0]
+      );
+      if (~ndx) {
+        joinPointIds.push(...this.attrib.lines[ndx].pointIds);
+        this.attrib.lines.splice(ndx, 1);
+      }
+      polygonLines.shift();
+    }
+
+    joinPointIds = Array.from(new Set(joinPointIds));
+    while (joinPointIds.length) {
+      const ndx = this.attrib.points.findIndex(
+        ({ id }) => id === joinPointIds[0]
+      );
+
+      if (~ndx && !this.attrib.points[ndx].rtk) {
+        this.attrib.points.splice(ndx, 1);
+      }
+      joinPointIds.shift();
+    }
+
+    this.attrib.polygons.splice(ndx, 1);
+  }
+
+  initIncFactory() {
+    super.initIncFactory();
+    this.incPointsFactory = incEntitysFactoryGenerate(
+      WholeLinePoint<any>,
+      this,
+      (point) => {
+        point.actShapeFactory = pointActShapeFactory as any;
+      }
+    );
+  }
+
+  editPolygon(polygonId?: string) {
+    this.activePointId.value = polygonId;
+    super.enterEditMode({
+      polygonId: polygonId,
+      pointAttribFactory: getPolygonPoint,
+      canOper: (tree, operShape) => {
+        return (
+          !tree.name.includes(WholeLinePoint.namespace) ||
+          operShape.name() === "anchor-point"
+        );
+      },
+      quitHandler: () => {
+        this.bus.emit("penEndHandler");
+      },
+      canDelPoint: (p) => !p.rtk,
+      quotePoint: false,
+    });
+    return super.leaveEditMode;
+  }
+
+  mounted(): void {
+    super.mounted();
+    let clearCursor: (() => void) | null = null;
+    this.container.stage.on("mousemove.anchor-move", (evt) => {
+      const isPoint = evt.target.name() === "anchor-move";
+      if (!isPoint) {
+        clearCursor && clearCursor();
+        clearCursor = null;
+        return;
+      }
+
+      if (this.editPolygonId.value) {
+        clearCursor = this.container.setCursor("move");
+      } else {
+        clearCursor = this.container.setCursor("pointer");
+      }
+    });
+
+    this.container.stage.on("click.anchor-move", (evt) => {
+      const point = shapeParentsEq(evt.target, (shape) =>
+        shape.id().startsWith(WholeLinePoint.namespace)
+      );
+      if (!point) {
+        this.activePointId.value = undefined;
+      }
+    });
+  }
+  destory(): void {
+    super.destory();
+    this.container.stage.off("mousemove.anchor-move click.anchor-move");
+  }
+}

+ 17 - 0
src/app/4dmap/type.ts

@@ -0,0 +1,17 @@
+import {
+  WholeLineLineAttrib,
+  WholeLinePointAttrib,
+  WholeLinePolygonAttrib,
+} from "../../board";
+
+export type PolygonsPointAttrib = WholeLinePointAttrib & {
+  rtk: boolean;
+  title: string;
+};
+export type PolygonsLineAttrib = WholeLineLineAttrib;
+
+export type PolygonsAttrib = {
+  lines: PolygonsLineAttrib[];
+  polygons: WholeLinePolygonAttrib[];
+  points: PolygonsPointAttrib[];
+};

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

@@ -144,6 +144,7 @@ export const penWholeLinePoygonsEditWithHelperMouse = <
   };
 
   let leaveEditMode = () => {
+    console.log("leaveEditMode");
     if (hasTouchEvents) {
       stage.off("touchstart.editPolygonsMode", touchstartHandler);
       stage.off("touchmove.editPolygonsMode", touchmoveHandler);
@@ -161,7 +162,6 @@ export const penWholeLinePoygonsEditWithHelperMouse = <
     helper.end();
     props.quitHandler && props.quitHandler();
   };
-
   if (hasTouchEvents) {
     stage.on("touchstart.editPolygonsMode", touchstartHandler);
     stage.on("touchmove.editPolygonsMode", touchmoveHandler);

+ 25 - 16
src/board/register.ts

@@ -19,11 +19,6 @@ export const register = <
     virtual.style.width = "100%";
     virtual.style.height = "100%";
 
-    if (!dom) {
-      virtual.style.width = "300px";
-      virtual.style.height = "300px";
-    }
-
     const container = new Container({
       dom: virtual,
       readonly,
@@ -41,6 +36,29 @@ export const register = <
         pluginApis[key] = plugin;
       }
     }
+
+    let mountedDom: HTMLDivElement | null = null;
+    const mount = (dom: HTMLDivElement) => {
+      if (virtual.parentElement) {
+        virtual.parentElement.removeChild(virtual);
+      }
+      console.log(virtual);
+      dom.appendChild(virtual);
+      virtual.style.width = "100%";
+      virtual.style.height = "100%";
+
+      container.stage.width(virtual.offsetWidth);
+      container.stage.width(virtual.offsetHeight);
+      mountedDom = dom;
+    };
+
+    if (!dom) {
+      virtual.style.width = "300px";
+      virtual.style.height = "300px";
+    } else {
+      mount(dom);
+    }
+
     return {
       types,
       tree: container,
@@ -57,17 +75,8 @@ export const register = <
         }
         container.destory();
       },
-      mount(dom: HTMLDivElement) {
-        if (virtual.parentElement) {
-          virtual.parentElement.removeChild(virtual);
-        }
-        dom.appendChild(virtual);
-        virtual.style.width = "100%";
-        virtual.style.height = "100%";
-
-        container.stage.width(virtual.offsetWidth);
-        container.stage.width(virtual.offsetHeight);
-      },
+      mountedDom,
+      mount,
       ...pluginApis,
     };
   };