|
@@ -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");
|
|
|
+ }
|
|
|
+}
|