polygons.ts 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291
  1. import { PolygonsAttrib, PolygonsPointAttrib } from "./type";
  2. import {
  3. incEntitysFactoryGenerate,
  4. Attrib,
  5. wholeLineStyle,
  6. getRealAbsoluteSize,
  7. PenEditWholeLine,
  8. WholeLinePoint,
  9. getWholeLinePolygonPoints,
  10. shapeParentsEq,
  11. openEntityDrag,
  12. WholeLineInc,
  13. } from "../../board";
  14. import { Group } from "konva/lib/Group";
  15. import { Path } from "konva/lib/shapes/Path";
  16. import { Circle } from "konva/lib/shapes/Circle";
  17. import { Label, Tag } from "konva/lib/shapes/Label";
  18. import { Text } from "konva/lib/shapes/Text";
  19. import { ref } from "vue";
  20. import mitt from "mitt";
  21. import { point } from "../../board/packages/whole-line/style";
  22. // 加点
  23. const getPolygonPoint = (position: number[]) => {
  24. const pointAttrib = {
  25. rtk: false,
  26. title: "",
  27. x: position[0],
  28. y: position[1],
  29. };
  30. return pointAttrib;
  31. };
  32. const pointActShapeFactory = (attrib: PolygonsPointAttrib, tree: any) => {
  33. const polygons = tree.parent as Polygons;
  34. const size = { width: 43, height: 44 };
  35. const out = new Path({
  36. 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`,
  37. strokeScaleEnabled: true,
  38. stroke: "#ffffff",
  39. strokeWidth: 1,
  40. });
  41. const inner = new Path({
  42. fill: "#fff",
  43. 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`,
  44. });
  45. const rect = new Circle({
  46. name: "anchor-move",
  47. radius: Math.min(size.width, size.height) / 2,
  48. fill: "rgba(0, 0, 0, 0)",
  49. offset: { x: -size.width / 2, y: -size.height / 2 },
  50. });
  51. const wlp = wholeLineStyle.pointShapeFactory();
  52. point.radius = 5;
  53. point.hitStrokeWidth = point.strokeWidth = 4;
  54. wlp.shape.name("anchor-point");
  55. const index = new Text({
  56. name: "text",
  57. text: `1`,
  58. fontFamily: "Calibri",
  59. fontSize: 12,
  60. padding: 5,
  61. offsetY: -8,
  62. fill: "#000",
  63. });
  64. const label = new Label({
  65. visible: false,
  66. opacity: 0.75,
  67. name: "label",
  68. offsetX: -size.width / 2,
  69. offsetY: -6,
  70. });
  71. label.add(
  72. new Tag({
  73. name: "tag",
  74. fill: "rgba(255, 255, 255, 0.8)",
  75. pointerDirection: "down",
  76. pointerWidth: 5,
  77. pointerHeight: 5,
  78. lineJoin: "round",
  79. shadowColor: "black",
  80. shadowBlur: 10,
  81. shadowOffsetX: 10,
  82. shadowOffsetY: 10,
  83. shadowOpacity: 0.5,
  84. }),
  85. new Text({
  86. name: "text",
  87. text: attrib.title || `P${attrib.id}`,
  88. fontFamily: "Calibri",
  89. fontSize: 10,
  90. padding: 5,
  91. fill: "#000",
  92. })
  93. );
  94. const offsetGroup = new Group();
  95. offsetGroup.add(out, inner, rect, label, index);
  96. offsetGroup.x(-size.width / 2);
  97. offsetGroup.y(-size.height);
  98. const group = new Group();
  99. group.add(offsetGroup, wlp.shape);
  100. const activeNdx = () => {
  101. if (polygons.editPolygonId.value) {
  102. const points = getWholeLinePolygonPoints(
  103. polygons.attrib,
  104. polygons.editPolygonId.value
  105. ).map(({ id }) => id);
  106. const ndx = points.indexOf(attrib.id);
  107. return ndx;
  108. }
  109. return -1;
  110. };
  111. const setStyle = () => {
  112. let [width, height] = getRealAbsoluteSize(group, [1, 1]);
  113. group.scale({ x: width, y: height });
  114. const ndx = activeNdx();
  115. if (~ndx) {
  116. index.text((ndx + 1).toString()).visible(true);
  117. index.offsetX(-rect.width() / 2 + index.width() / 2);
  118. } else {
  119. index.visible(false);
  120. }
  121. };
  122. const commonStyle = () => {
  123. out.fill(attrib.rtk ? "rgba(230, 162, 60, 1)" : "#409EFF");
  124. label.visible(false);
  125. wlp.common();
  126. };
  127. const result = {
  128. shape: group,
  129. common: commonStyle,
  130. hover: () => {
  131. label.visible(true);
  132. },
  133. setData(data: number[]) {
  134. setStyle();
  135. group.x(data[0]);
  136. group.y(data[1]);
  137. label.visible(polygons.activePointId.value === attrib.id);
  138. },
  139. draging() {
  140. if (polygons.editPolygonId.value && !attrib.rtk) {
  141. out.fill("#e0403c");
  142. }
  143. },
  144. active() {
  145. polygons.activePointId.value = attrib.id;
  146. polygons.bus.emit("clickPoint", attrib);
  147. },
  148. };
  149. return result;
  150. };
  151. export class Polygons extends PenEditWholeLine<PolygonsAttrib & Attrib> {
  152. bus = mitt<{ clickPoint: PolygonsPointAttrib; penEndHandler: void }>();
  153. activePointId = ref<string>();
  154. dragAttach(inc: WholeLineInc<PolygonsAttrib & Attrib>) {
  155. inc.pointEntityInc.adds.forEach((point) => {
  156. openEntityDrag(point, {
  157. readyHandler: (attrib) => {
  158. return [attrib.x, attrib.y];
  159. },
  160. moveHandler: (pointAttrib, move) => {
  161. if (this.editPolygonId.value && !pointAttrib.rtk) {
  162. pointAttrib.x = move[0];
  163. pointAttrib.y = move[1];
  164. }
  165. },
  166. });
  167. point.enableMouseAct(point.actShape);
  168. });
  169. inc.lineEntityInc.adds.forEach((line) => {
  170. line.enableMouseAct(line.actShape);
  171. });
  172. inc.polygonEntityInc.adds.forEach((py) => {
  173. py.enableMouseAct(py.actShape);
  174. });
  175. }
  176. removePolygon(polygonId: string) {
  177. const ndx = this.attrib.polygons.findIndex(({ id }) => id === polygonId);
  178. if (!~ndx) {
  179. return;
  180. }
  181. const polygonLines = this.attrib.polygons[ndx].lineIds;
  182. let joinPointIds: string[] = [];
  183. while (polygonLines.length) {
  184. const ndx = this.attrib.lines.findIndex(
  185. ({ id }) => id === polygonLines[0]
  186. );
  187. if (~ndx) {
  188. joinPointIds.push(...this.attrib.lines[ndx].pointIds);
  189. this.attrib.lines.splice(ndx, 1);
  190. }
  191. polygonLines.shift();
  192. }
  193. joinPointIds = Array.from(new Set(joinPointIds));
  194. while (joinPointIds.length) {
  195. const ndx = this.attrib.points.findIndex(
  196. ({ id }) => id === joinPointIds[0]
  197. );
  198. if (~ndx && !this.attrib.points[ndx].rtk) {
  199. this.attrib.points.splice(ndx, 1);
  200. }
  201. joinPointIds.shift();
  202. }
  203. this.attrib.polygons.splice(ndx, 1);
  204. }
  205. initIncFactory() {
  206. super.initIncFactory();
  207. this.incPointsFactory = incEntitysFactoryGenerate(
  208. WholeLinePoint<any>,
  209. this,
  210. (point) => {
  211. point.actShapeFactory = pointActShapeFactory as any;
  212. }
  213. );
  214. }
  215. editPolygon(polygonId?: string) {
  216. this.activePointId.value = polygonId;
  217. super.enterEditMode({
  218. polygonId: polygonId,
  219. pointAttribFactory: getPolygonPoint,
  220. canOper: (tree, operShape) => {
  221. return (
  222. !tree.name.includes(WholeLinePoint.namespace) ||
  223. operShape.name() === "anchor-point"
  224. );
  225. },
  226. quitHandler: () => {
  227. this.bus.emit("penEndHandler");
  228. },
  229. canDelPoint: (p) => !p.rtk,
  230. quotePoint: false,
  231. });
  232. return super.leaveEditMode;
  233. }
  234. mounted(): void {
  235. super.mounted();
  236. let clearCursor: (() => void) | null = null;
  237. this.container.stage.on("mousemove.anchor-move", (evt) => {
  238. const isPoint = evt.target.name() === "anchor-move";
  239. if (!isPoint) {
  240. clearCursor && clearCursor();
  241. clearCursor = null;
  242. return;
  243. }
  244. if (this.editPolygonId.value) {
  245. clearCursor = this.container.setCursor("move");
  246. } else {
  247. clearCursor = this.container.setCursor("pointer");
  248. }
  249. });
  250. this.container.stage.on("click.anchor-move", (evt) => {
  251. const point = shapeParentsEq(evt.target, (shape) =>
  252. shape.id().startsWith(WholeLinePoint.namespace)
  253. );
  254. if (!point) {
  255. this.activePointId.value = undefined;
  256. }
  257. });
  258. }
  259. destory(): void {
  260. super.destory();
  261. this.container.stage.off("mousemove.anchor-move click.anchor-move");
  262. }
  263. }