@antv/infographic 0.2.13 → 0.2.15

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (241) hide show
  1. package/README.md +12 -5
  2. package/README.zh-CN.md +12 -5
  3. package/dist/infographic.min.js +180 -171
  4. package/dist/infographic.min.js.map +1 -1
  5. package/esm/designs/structures/index.d.ts +1 -0
  6. package/esm/designs/structures/index.js +1 -0
  7. package/esm/designs/structures/relation-dagre-flow.js +4 -139
  8. package/esm/designs/structures/sequence-interaction.d.ts +54 -0
  9. package/esm/designs/structures/sequence-interaction.js +440 -0
  10. package/esm/designs/utils/geometry.d.ts +44 -0
  11. package/esm/designs/utils/geometry.js +244 -0
  12. package/esm/designs/utils/index.d.ts +1 -0
  13. package/esm/designs/utils/index.js +1 -0
  14. package/esm/editor/commands/UpdateOptions.d.ts +4 -4
  15. package/esm/editor/commands/UpdateOptions.js +6 -3
  16. package/esm/editor/editor.d.ts +5 -1
  17. package/esm/editor/editor.js +16 -5
  18. package/esm/editor/index.d.ts +1 -0
  19. package/esm/editor/index.js +1 -0
  20. package/esm/editor/interactions/brush-select.d.ts +0 -1
  21. package/esm/editor/interactions/brush-select.js +2 -10
  22. package/esm/editor/interactions/drag-canvas.d.ts +35 -0
  23. package/esm/editor/interactions/drag-canvas.js +161 -0
  24. package/esm/editor/interactions/drag-element.js +4 -3
  25. package/esm/editor/interactions/index.d.ts +1 -0
  26. package/esm/editor/interactions/index.js +1 -0
  27. package/esm/editor/interactions/zoom-wheel.d.ts +9 -0
  28. package/esm/editor/interactions/zoom-wheel.js +32 -15
  29. package/esm/editor/managers/index.d.ts +1 -0
  30. package/esm/editor/managers/index.js +1 -0
  31. package/esm/editor/managers/state.d.ts +4 -2
  32. package/esm/editor/managers/state.js +14 -13
  33. package/esm/editor/managers/sync-registry.d.ts +16 -0
  34. package/esm/editor/managers/sync-registry.js +51 -0
  35. package/esm/editor/plugins/{edit-bar/components → components}/button.js +1 -1
  36. package/esm/editor/plugins/{edit-bar/components → components}/color-picker.js +1 -1
  37. package/esm/editor/plugins/{edit-bar/components → components}/icons.d.ts +1 -0
  38. package/esm/editor/plugins/{edit-bar/components → components}/icons.js +1 -0
  39. package/esm/editor/plugins/{edit-bar/components → components}/popover.js +2 -2
  40. package/esm/editor/plugins/{edit-bar/components → components}/select.js +1 -1
  41. package/esm/editor/plugins/core-sync.d.ts +8 -0
  42. package/esm/editor/plugins/core-sync.js +30 -0
  43. package/esm/editor/plugins/edit-bar/edit-items/align-elements.js +1 -1
  44. package/esm/editor/plugins/edit-bar/edit-items/font-align.js +1 -1
  45. package/esm/editor/plugins/edit-bar/edit-items/font-color.js +1 -1
  46. package/esm/editor/plugins/edit-bar/edit-items/font-family.js +1 -1
  47. package/esm/editor/plugins/edit-bar/edit-items/font-size.js +1 -1
  48. package/esm/editor/plugins/edit-bar/edit-items/icon-color.js +1 -1
  49. package/esm/editor/plugins/edit-bar/index.d.ts +2 -2
  50. package/esm/editor/plugins/edit-bar/index.js +1 -1
  51. package/esm/editor/plugins/index.d.ts +2 -0
  52. package/esm/editor/plugins/index.js +2 -0
  53. package/esm/editor/plugins/reset-viewbox.d.ts +33 -0
  54. package/esm/editor/plugins/reset-viewbox.js +186 -0
  55. package/esm/editor/types/editor.d.ts +14 -0
  56. package/esm/editor/types/index.d.ts +1 -0
  57. package/esm/editor/types/interaction.d.ts +9 -0
  58. package/esm/editor/types/state.d.ts +4 -2
  59. package/esm/editor/types/sync.d.ts +27 -0
  60. package/esm/editor/types/sync.js +1 -0
  61. package/esm/editor/utils/data.js +3 -1
  62. package/esm/editor/utils/event.d.ts +1 -0
  63. package/esm/editor/utils/event.js +8 -0
  64. package/esm/editor/utils/index.d.ts +1 -0
  65. package/esm/editor/utils/index.js +1 -0
  66. package/esm/editor/utils/object.d.ts +15 -0
  67. package/esm/editor/utils/object.js +77 -0
  68. package/esm/index.d.ts +4 -3
  69. package/esm/index.js +3 -2
  70. package/esm/options/types.d.ts +7 -0
  71. package/esm/runtime/Infographic.js +20 -7
  72. package/esm/runtime/options.js +7 -2
  73. package/esm/syntax/index.js +40 -20
  74. package/esm/syntax/relations.js +26 -2
  75. package/esm/syntax/schema.js +1 -0
  76. package/esm/templates/built-in.js +27 -2
  77. package/esm/templates/sequence-interaction.d.ts +2 -0
  78. package/esm/templates/sequence-interaction.js +76 -0
  79. package/esm/types/data.d.ts +1 -0
  80. package/esm/utils/index.d.ts +1 -0
  81. package/esm/utils/index.js +1 -0
  82. package/esm/utils/measure-text.js +40 -9
  83. package/esm/utils/padding.d.ts +1 -0
  84. package/esm/utils/padding.js +6 -2
  85. package/esm/utils/types.d.ts +16 -0
  86. package/esm/utils/types.js +12 -0
  87. package/esm/version.d.ts +1 -1
  88. package/esm/version.js +1 -1
  89. package/lib/designs/structures/index.d.ts +1 -0
  90. package/lib/designs/structures/index.js +1 -0
  91. package/lib/designs/structures/relation-dagre-flow.js +5 -140
  92. package/lib/designs/structures/sequence-interaction.d.ts +54 -0
  93. package/lib/designs/structures/sequence-interaction.js +444 -0
  94. package/lib/designs/utils/geometry.d.ts +44 -0
  95. package/lib/designs/utils/geometry.js +256 -0
  96. package/lib/designs/utils/index.d.ts +1 -0
  97. package/lib/designs/utils/index.js +1 -0
  98. package/lib/editor/commands/UpdateOptions.d.ts +4 -4
  99. package/lib/editor/commands/UpdateOptions.js +6 -3
  100. package/lib/editor/editor.d.ts +5 -1
  101. package/lib/editor/editor.js +16 -5
  102. package/lib/editor/index.d.ts +1 -0
  103. package/lib/editor/index.js +1 -0
  104. package/lib/editor/interactions/brush-select.d.ts +0 -1
  105. package/lib/editor/interactions/brush-select.js +1 -9
  106. package/lib/editor/interactions/drag-canvas.d.ts +35 -0
  107. package/lib/editor/interactions/drag-canvas.js +165 -0
  108. package/lib/editor/interactions/drag-element.js +4 -3
  109. package/lib/editor/interactions/index.d.ts +1 -0
  110. package/lib/editor/interactions/index.js +3 -1
  111. package/lib/editor/interactions/zoom-wheel.d.ts +9 -0
  112. package/lib/editor/interactions/zoom-wheel.js +32 -15
  113. package/lib/editor/managers/index.d.ts +1 -0
  114. package/lib/editor/managers/index.js +1 -0
  115. package/lib/editor/managers/state.d.ts +4 -2
  116. package/lib/editor/managers/state.js +12 -11
  117. package/lib/editor/managers/sync-registry.d.ts +16 -0
  118. package/lib/editor/managers/sync-registry.js +55 -0
  119. package/lib/editor/plugins/{edit-bar/components → components}/button.js +1 -1
  120. package/lib/editor/plugins/{edit-bar/components → components}/color-picker.js +1 -1
  121. package/lib/editor/plugins/{edit-bar/components → components}/icons.d.ts +1 -0
  122. package/lib/editor/plugins/{edit-bar/components → components}/icons.js +2 -1
  123. package/lib/editor/plugins/{edit-bar/components → components}/popover.js +2 -2
  124. package/lib/editor/plugins/{edit-bar/components → components}/select.js +1 -1
  125. package/lib/editor/plugins/core-sync.d.ts +8 -0
  126. package/lib/editor/plugins/core-sync.js +34 -0
  127. package/lib/editor/plugins/edit-bar/edit-items/align-elements.js +1 -1
  128. package/lib/editor/plugins/edit-bar/edit-items/font-align.js +1 -1
  129. package/lib/editor/plugins/edit-bar/edit-items/font-color.js +1 -1
  130. package/lib/editor/plugins/edit-bar/edit-items/font-family.js +1 -1
  131. package/lib/editor/plugins/edit-bar/edit-items/font-size.js +1 -1
  132. package/lib/editor/plugins/edit-bar/edit-items/icon-color.js +1 -1
  133. package/lib/editor/plugins/edit-bar/index.d.ts +2 -2
  134. package/lib/editor/plugins/edit-bar/index.js +1 -1
  135. package/lib/editor/plugins/index.d.ts +2 -0
  136. package/lib/editor/plugins/index.js +5 -1
  137. package/lib/editor/plugins/reset-viewbox.d.ts +33 -0
  138. package/lib/editor/plugins/reset-viewbox.js +190 -0
  139. package/lib/editor/types/editor.d.ts +14 -0
  140. package/lib/editor/types/index.d.ts +1 -0
  141. package/lib/editor/types/interaction.d.ts +9 -0
  142. package/lib/editor/types/state.d.ts +4 -2
  143. package/lib/editor/types/sync.d.ts +27 -0
  144. package/lib/editor/types/sync.js +2 -0
  145. package/lib/editor/utils/data.js +3 -1
  146. package/lib/editor/utils/event.d.ts +1 -0
  147. package/lib/editor/utils/event.js +9 -0
  148. package/lib/editor/utils/index.d.ts +1 -0
  149. package/lib/editor/utils/index.js +1 -0
  150. package/lib/editor/utils/object.d.ts +15 -0
  151. package/lib/editor/utils/object.js +80 -0
  152. package/lib/index.d.ts +4 -3
  153. package/lib/index.js +9 -2
  154. package/lib/options/types.d.ts +7 -0
  155. package/lib/runtime/Infographic.js +19 -6
  156. package/lib/runtime/options.js +6 -1
  157. package/lib/syntax/index.js +40 -20
  158. package/lib/syntax/relations.js +26 -2
  159. package/lib/syntax/schema.js +1 -0
  160. package/lib/templates/built-in.js +27 -2
  161. package/lib/templates/sequence-interaction.d.ts +2 -0
  162. package/lib/templates/sequence-interaction.js +79 -0
  163. package/lib/types/data.d.ts +1 -0
  164. package/lib/utils/index.d.ts +1 -0
  165. package/lib/utils/index.js +1 -0
  166. package/lib/utils/measure-text.js +39 -8
  167. package/lib/utils/padding.d.ts +1 -0
  168. package/lib/utils/padding.js +7 -2
  169. package/lib/utils/types.d.ts +16 -0
  170. package/lib/utils/types.js +13 -0
  171. package/lib/version.d.ts +1 -1
  172. package/lib/version.js +1 -1
  173. package/package.json +1 -1
  174. package/src/designs/structures/index.ts +1 -0
  175. package/src/designs/structures/relation-dagre-flow.tsx +14 -178
  176. package/src/designs/structures/sequence-interaction.tsx +885 -0
  177. package/src/designs/utils/geometry.tsx +315 -0
  178. package/src/designs/utils/index.ts +1 -0
  179. package/src/editor/commands/UpdateOptions.ts +11 -6
  180. package/src/editor/editor.ts +26 -5
  181. package/src/editor/index.ts +1 -0
  182. package/src/editor/interactions/brush-select.ts +2 -8
  183. package/src/editor/interactions/drag-canvas.ts +203 -0
  184. package/src/editor/interactions/drag-element.ts +5 -4
  185. package/src/editor/interactions/index.ts +1 -0
  186. package/src/editor/interactions/zoom-wheel.ts +49 -13
  187. package/src/editor/managers/index.ts +1 -0
  188. package/src/editor/managers/state.ts +21 -21
  189. package/src/editor/managers/sync-registry.ts +66 -0
  190. package/src/editor/plugins/{edit-bar/components → components}/button.ts +1 -1
  191. package/src/editor/plugins/{edit-bar/components → components}/color-picker.ts +1 -1
  192. package/src/editor/plugins/{edit-bar/components → components}/icons.ts +4 -0
  193. package/src/editor/plugins/{edit-bar/components → components}/popover.ts +2 -2
  194. package/src/editor/plugins/{edit-bar/components → components}/select.ts +1 -1
  195. package/src/editor/plugins/core-sync.ts +44 -0
  196. package/src/editor/plugins/edit-bar/edit-items/align-elements.ts +2 -2
  197. package/src/editor/plugins/edit-bar/edit-items/font-align.ts +1 -1
  198. package/src/editor/plugins/edit-bar/edit-items/font-color.ts +1 -1
  199. package/src/editor/plugins/edit-bar/edit-items/font-family.ts +1 -1
  200. package/src/editor/plugins/edit-bar/edit-items/font-size.ts +3 -3
  201. package/src/editor/plugins/edit-bar/edit-items/icon-color.ts +1 -1
  202. package/src/editor/plugins/edit-bar/index.ts +2 -2
  203. package/src/editor/plugins/index.ts +2 -0
  204. package/src/editor/plugins/reset-viewbox.ts +258 -0
  205. package/src/editor/types/editor.ts +18 -0
  206. package/src/editor/types/index.ts +1 -0
  207. package/src/editor/types/interaction.ts +31 -0
  208. package/src/editor/types/state.ts +14 -2
  209. package/src/editor/types/sync.ts +33 -0
  210. package/src/editor/utils/data.ts +2 -1
  211. package/src/editor/utils/event.ts +7 -0
  212. package/src/editor/utils/index.ts +1 -0
  213. package/src/editor/utils/object.ts +116 -0
  214. package/src/index.ts +26 -2
  215. package/src/options/types.ts +11 -0
  216. package/src/runtime/Infographic.tsx +27 -17
  217. package/src/runtime/options.ts +8 -1
  218. package/src/syntax/index.ts +51 -18
  219. package/src/syntax/relations.ts +29 -2
  220. package/src/syntax/schema.ts +1 -0
  221. package/src/templates/built-in.ts +30 -0
  222. package/src/templates/sequence-interaction.ts +101 -0
  223. package/src/types/data.ts +1 -0
  224. package/src/utils/index.ts +1 -0
  225. package/src/utils/measure-text.ts +41 -9
  226. package/src/utils/padding.ts +10 -2
  227. package/src/utils/types.ts +61 -0
  228. package/src/version.ts +1 -1
  229. /package/esm/editor/plugins/{edit-bar/components → components}/button.d.ts +0 -0
  230. /package/esm/editor/plugins/{edit-bar/components → components}/color-picker.d.ts +0 -0
  231. /package/esm/editor/plugins/{edit-bar/components → components}/index.d.ts +0 -0
  232. /package/esm/editor/plugins/{edit-bar/components → components}/index.js +0 -0
  233. /package/esm/editor/plugins/{edit-bar/components → components}/popover.d.ts +0 -0
  234. /package/esm/editor/plugins/{edit-bar/components → components}/select.d.ts +0 -0
  235. /package/lib/editor/plugins/{edit-bar/components → components}/button.d.ts +0 -0
  236. /package/lib/editor/plugins/{edit-bar/components → components}/color-picker.d.ts +0 -0
  237. /package/lib/editor/plugins/{edit-bar/components → components}/index.d.ts +0 -0
  238. /package/lib/editor/plugins/{edit-bar/components → components}/index.js +0 -0
  239. /package/lib/editor/plugins/{edit-bar/components → components}/popover.d.ts +0 -0
  240. /package/lib/editor/plugins/{edit-bar/components → components}/select.d.ts +0 -0
  241. /package/src/editor/plugins/{edit-bar/components → components}/index.ts +0 -0
@@ -0,0 +1,244 @@
1
+ import { jsx as _jsx } from "../../jsx-runtime.js";
2
+ import { Path, Polygon } from '../../jsx/index.js';
3
+ export const getMidPoint = (points) => {
4
+ if (points.length === 0)
5
+ return null;
6
+ if (points.length === 1)
7
+ return points[0];
8
+ let total = 0;
9
+ const segments = [];
10
+ for (let i = 0; i < points.length - 1; i += 1) {
11
+ const start = points[i];
12
+ const end = points[i + 1];
13
+ const length = Math.hypot(end[0] - start[0], end[1] - start[1]);
14
+ segments.push({ length, start, end });
15
+ total += length;
16
+ }
17
+ if (total === 0)
18
+ return points[0];
19
+ let target = total / 2;
20
+ for (let i = 0; i < segments.length; i += 1) {
21
+ const segment = segments[i];
22
+ if (target <= segment.length || i === segments.length - 1) {
23
+ const ratio = segment.length === 0
24
+ ? 0
25
+ : Math.max(0, Math.min(1, target / segment.length));
26
+ return [
27
+ segment.start[0] + (segment.end[0] - segment.start[0]) * ratio,
28
+ segment.start[1] + (segment.end[1] - segment.start[1]) * ratio,
29
+ ];
30
+ }
31
+ target -= segment.length;
32
+ }
33
+ return points[Math.floor(points.length / 2)];
34
+ };
35
+ export const createStraightPath = (points, dx, dy) => points
36
+ .map(([x, y], index) => {
37
+ const prefix = index === 0 ? 'M' : 'L';
38
+ return `${prefix} ${x + dx} ${y + dy}`;
39
+ })
40
+ .join(' ');
41
+ export const createRoundedPath = (points, radius, dx, dy) => {
42
+ if (points.length < 2)
43
+ return '';
44
+ const clamp = (value, min, max) => Math.min(max, Math.max(min, value));
45
+ const toPoint = ([x, y]) => ({
46
+ x: x + dx,
47
+ y: y + dy,
48
+ });
49
+ const output = [];
50
+ const first = toPoint(points[0]);
51
+ output.push(`M ${first.x} ${first.y}`);
52
+ if (points.length === 2) {
53
+ const last = toPoint(points[1]);
54
+ output.push(`L ${last.x} ${last.y}`);
55
+ return output.join(' ');
56
+ }
57
+ for (let i = 1; i < points.length - 1; i += 1) {
58
+ const prev = points[i - 1];
59
+ const curr = points[i];
60
+ const next = points[i + 1];
61
+ const v0x = curr[0] - prev[0];
62
+ const v0y = curr[1] - prev[1];
63
+ const v1x = next[0] - curr[0];
64
+ const v1y = next[1] - curr[1];
65
+ const d0 = Math.hypot(v0x, v0y);
66
+ const d1 = Math.hypot(v1x, v1y);
67
+ if (d0 === 0 || d1 === 0) {
68
+ const currPoint = toPoint(curr);
69
+ output.push(`L ${currPoint.x} ${currPoint.y}`);
70
+ continue;
71
+ }
72
+ const r = clamp(radius, 0, Math.min(d0, d1) / 2);
73
+ if (r === 0) {
74
+ const currPoint = toPoint(curr);
75
+ output.push(`L ${currPoint.x} ${currPoint.y}`);
76
+ continue;
77
+ }
78
+ const u0x = v0x / d0;
79
+ const u0y = v0y / d0;
80
+ const u1x = v1x / d1;
81
+ const u1y = v1y / d1;
82
+ const start = toPoint([curr[0] - u0x * r, curr[1] - u0y * r]);
83
+ const end = toPoint([curr[0] + u1x * r, curr[1] + u1y * r]);
84
+ output.push(`L ${start.x} ${start.y}`);
85
+ const currPoint = toPoint(curr);
86
+ output.push(`Q ${currPoint.x} ${currPoint.y} ${end.x} ${end.y}`);
87
+ }
88
+ const last = toPoint(points[points.length - 1]);
89
+ output.push(`L ${last.x} ${last.y}`);
90
+ return output.join(' ');
91
+ };
92
+ export const createArrowElements = (x, y, angle, type, fillColor, edgeWidth, arrowSize) => {
93
+ const ux = Math.cos(angle);
94
+ const uy = Math.sin(angle);
95
+ const px = -uy;
96
+ const py = ux;
97
+ const length = arrowSize;
98
+ const halfWidth = arrowSize * 0.55;
99
+ if (type === 'arrow') {
100
+ const leftX = x - ux * length + px * halfWidth;
101
+ const leftY = y - uy * length + py * halfWidth;
102
+ const rightX = x - ux * length - px * halfWidth;
103
+ const rightY = y - uy * length - py * halfWidth;
104
+ return [
105
+ _jsx(Path, { d: `M ${leftX} ${leftY} L ${x} ${y} L ${rightX} ${rightY}`, stroke: fillColor, strokeWidth: Math.max(1.5, edgeWidth), strokeLinecap: "round", strokeLinejoin: "round", fill: "none" }),
106
+ ];
107
+ }
108
+ if (type === 'diamond') {
109
+ const diamondLength = length * 1.25;
110
+ const diamondWidth = halfWidth * 0.75;
111
+ const midX = x - ux * diamondLength * 0.5;
112
+ const midY = y - uy * diamondLength * 0.5;
113
+ const diamondPoints = [
114
+ { x, y },
115
+ { x: midX + px * diamondWidth, y: midY + py * diamondWidth },
116
+ { x: x - ux * diamondLength, y: y - uy * diamondLength },
117
+ { x: midX - px * diamondWidth, y: midY - py * diamondWidth },
118
+ ];
119
+ return [
120
+ _jsx(Polygon, { points: diamondPoints, fill: fillColor, stroke: fillColor, strokeWidth: Math.max(1, edgeWidth * 0.8) }),
121
+ ];
122
+ }
123
+ const trianglePoints = [
124
+ { x, y },
125
+ {
126
+ x: x - ux * length + px * halfWidth,
127
+ y: y - uy * length + py * halfWidth,
128
+ },
129
+ {
130
+ x: x - ux * length - px * halfWidth,
131
+ y: y - uy * length - py * halfWidth,
132
+ },
133
+ ];
134
+ return [
135
+ _jsx(Polygon, { points: trianglePoints, fill: fillColor, stroke: fillColor, strokeWidth: Math.max(1, edgeWidth * 0.8) }),
136
+ ];
137
+ };
138
+ // LT: Left Top (radio), LC: Left Center (1/2), LB: Left Bottom (1 - radio)
139
+ // RT: Right Top (radio), RC: Right Center (1/2), RB: Right Bottom (1 - radio)
140
+ export const getNodesAnchors = (node) => {
141
+ const { x, y, width, height, radio = 0.25 } = node;
142
+ const q1H = height * radio;
143
+ const halfH = height * 0.5;
144
+ const q3H = height * (1 - radio);
145
+ return {
146
+ LT: { x, y: y + q1H },
147
+ LC: { x, y: y + halfH },
148
+ LB: { x, y: y + q3H },
149
+ RT: { x: x + width, y: y + q1H },
150
+ RC: { x: x + width, y: y + halfH },
151
+ RB: { x: x + width, y: y + q3H },
152
+ };
153
+ };
154
+ export const getTangentAngle = (points, t) => {
155
+ const len = points.length;
156
+ // Cubic Bezier (Self loop)
157
+ if (len === 4) {
158
+ const p0 = points[0], p1 = points[1], p2 = points[2], p3 = points[3];
159
+ if (t === 0) {
160
+ return Math.atan2(p1[1] - p0[1], p1[0] - p0[0]);
161
+ }
162
+ else {
163
+ return Math.atan2(p3[1] - p2[1], p3[0] - p2[0]);
164
+ }
165
+ }
166
+ // Quad Bezier (Curved)
167
+ if (len === 3) {
168
+ const p0 = points[0], p1 = points[1], p2 = points[2];
169
+ if (t === 0) {
170
+ return Math.atan2(p1[1] - p0[1], p1[0] - p0[0]);
171
+ }
172
+ else {
173
+ return Math.atan2(p2[1] - p1[1], p2[0] - p1[0]);
174
+ }
175
+ }
176
+ // Line
177
+ if (len === 2) {
178
+ const p0 = points[0], p1 = points[1];
179
+ const angle = Math.atan2(p1[1] - p0[1], p1[0] - p0[0]);
180
+ return angle;
181
+ }
182
+ return 0;
183
+ };
184
+ /**
185
+ * 计算贝塞尔曲线上任意 t (0-1) 位置的点
186
+ */
187
+ export const getPointAtT = (points, t = 0.5) => {
188
+ const len = points.length;
189
+ if (len === 4) {
190
+ const [p0, p1, p2, p3] = points;
191
+ const mt = 1 - t;
192
+ // B(t) = (1-t)^3*P0 + 3(1-t)^2*t*P1 + 3(1-t)*t^2*P2 + t^3*P3
193
+ return [
194
+ Math.pow(mt, 3) * p0[0] +
195
+ 3 * Math.pow(mt, 2) * t * p1[0] +
196
+ 3 * mt * Math.pow(t, 2) * p2[0] +
197
+ Math.pow(t, 3) * p3[0],
198
+ Math.pow(mt, 3) * p0[1] +
199
+ 3 * Math.pow(mt, 2) * t * p1[1] +
200
+ 3 * mt * Math.pow(t, 2) * p2[1] +
201
+ Math.pow(t, 3) * p3[1],
202
+ ];
203
+ }
204
+ if (len === 3) {
205
+ const [p0, p1, p2] = points;
206
+ const mt = 1 - t;
207
+ // B(t) = (1-t)^2*P0 + 2(1-t)*t*P1 + t^2*P2
208
+ return [
209
+ Math.pow(mt, 2) * p0[0] + 2 * mt * t * p1[0] + Math.pow(t, 2) * p2[0],
210
+ Math.pow(mt, 2) * p0[1] + 2 * mt * t * p1[1] + Math.pow(t, 2) * p2[1],
211
+ ];
212
+ }
213
+ if (len === 2) {
214
+ const [p0, p1] = points;
215
+ return [p0[0] + (p1[0] - p0[0]) * t, p0[1] + (p1[1] - p0[1]) * t];
216
+ }
217
+ return points[0] || [0, 0];
218
+ };
219
+ export const getLabelPosition = (points, selfLoopOffset = 10) => {
220
+ const len = points.length;
221
+ // 默认取中点
222
+ const labelPoint = getPointAtT(points);
223
+ if (len === 4) {
224
+ // 针对自连接(len=4)的特殊偏移处理
225
+ labelPoint[0] += selfLoopOffset;
226
+ }
227
+ return labelPoint;
228
+ };
229
+ export const getEdgePathD = (points) => {
230
+ const len = points.length;
231
+ if (len === 4) {
232
+ const [p0, p1, p2, p3] = points;
233
+ return `M ${p0[0]} ${p0[1]} C ${p1[0]} ${p1[1]} ${p2[0]} ${p2[1]} ${p3[0]} ${p3[1]}`;
234
+ }
235
+ if (len === 3) {
236
+ const [p0, p1, p2] = points;
237
+ return `M ${p0[0]} ${p0[1]} Q ${p1[0]} ${p1[1]} ${p2[0]} ${p2[1]}`;
238
+ }
239
+ if (len === 2) {
240
+ const [p0, p1] = points;
241
+ return `M ${p0[0]} ${p0[1]} L ${p1[0]} ${p1[1]}`;
242
+ }
243
+ return '';
244
+ };
@@ -1,4 +1,5 @@
1
1
  export * from './color';
2
+ export * from './geometry';
2
3
  export * from './hierarchy-color';
3
4
  export * from './item';
4
5
  export * from './normalize-percent';
@@ -1,4 +1,5 @@
1
1
  export * from './color.js';
2
+ export * from './geometry.js';
2
3
  export * from './hierarchy-color.js';
3
4
  export * from './item.js';
4
5
  export * from './normalize-percent.js';
@@ -1,14 +1,14 @@
1
- import type { ParsedInfographicOptions } from '../../options';
1
+ import type { UpdatableInfographicOptions } from '../../options';
2
2
  import type { ICommand, IStateManager } from '../types';
3
3
  export declare class UpdateOptionsCommand implements ICommand {
4
4
  private options;
5
5
  private original?;
6
- constructor(options: Partial<ParsedInfographicOptions>, original?: ParsedInfographicOptions | undefined);
6
+ constructor(options: UpdatableInfographicOptions, original?: UpdatableInfographicOptions | undefined);
7
7
  apply(state: IStateManager): Promise<void>;
8
8
  undo(state: IStateManager): Promise<void>;
9
9
  serialize(): {
10
10
  type: string;
11
- options: Partial<ParsedInfographicOptions>;
12
- original: ParsedInfographicOptions | undefined;
11
+ options: Partial<Omit<import("../../options").ParsedInfographicOptions, "container">>;
12
+ original: Partial<Omit<import("../../options").ParsedInfographicOptions, "container">> | undefined;
13
13
  };
14
14
  }
@@ -14,11 +14,14 @@ export class UpdateOptionsCommand {
14
14
  }
15
15
  apply(state) {
16
16
  return __awaiter(this, void 0, void 0, function* () {
17
- const prev = state.getOptions();
18
17
  if (!this.original) {
19
- this.original = prev;
18
+ const prev = state.getOptions();
19
+ this.original = {};
20
+ Object.keys(this.options).forEach((key) => {
21
+ this.original[key] = prev[key];
22
+ });
20
23
  }
21
- state.updateOptions(Object.assign(Object.assign({}, prev), this.options));
24
+ state.updateOptions(this.options);
22
25
  });
23
26
  }
24
27
  undo(state) {
@@ -1,7 +1,7 @@
1
1
  import type { ParsedInfographicOptions } from '../options';
2
2
  import type { IEventEmitter } from '../types';
3
3
  import { InteractionManager } from './managers';
4
- import type { ICommandManager, IEditor, IPluginManager, IStateManager } from './types';
4
+ import type { ICommandManager, IEditor, IPluginManager, IStateManager, ISyncRegistry, SyncHandler } from './types';
5
5
  export declare class Editor implements IEditor {
6
6
  private emitter;
7
7
  private document;
@@ -10,7 +10,11 @@ export declare class Editor implements IEditor {
10
10
  commander: ICommandManager;
11
11
  plugin: IPluginManager;
12
12
  interaction: InteractionManager;
13
+ syncRegistry: ISyncRegistry;
13
14
  constructor(emitter: IEventEmitter, document: SVGSVGElement, options: ParsedInfographicOptions);
15
+ registerSync(path: string, handler: SyncHandler, options?: {
16
+ immediate?: boolean;
17
+ }): () => void;
14
18
  getDocument(): SVGSVGElement;
15
19
  destroy(): void;
16
20
  }
@@ -1,4 +1,6 @@
1
1
  import { CommandManager, InteractionManager, PluginManager, StateManager, } from './managers/index.js';
2
+ import { SyncRegistry } from './managers/sync-registry.js';
3
+ import { CoreSyncPlugin } from './plugins/index.js';
2
4
  export class Editor {
3
5
  constructor(emitter, document, options) {
4
6
  this.emitter = emitter;
@@ -12,6 +14,12 @@ export class Editor {
12
14
  const state = new StateManager();
13
15
  const plugin = new PluginManager();
14
16
  const interaction = new InteractionManager();
17
+ const syncRegistry = new SyncRegistry(() => state.getOptions());
18
+ this.commander = commander;
19
+ this.state = state;
20
+ this.plugin = plugin;
21
+ this.interaction = interaction;
22
+ this.syncRegistry = syncRegistry;
15
23
  commander.init({ state, emitter });
16
24
  state.init({
17
25
  emitter,
@@ -19,12 +27,15 @@ export class Editor {
19
27
  commander,
20
28
  options,
21
29
  });
30
+ // Load core plugin: CoreSyncPlugin (handles viewBox/padding sync)
31
+ const corePlugin = new CoreSyncPlugin();
32
+ const userPlugins = options.plugins || [];
22
33
  plugin.init({
23
34
  emitter,
24
35
  editor: this,
25
36
  commander,
26
37
  state,
27
- }, options.plugins);
38
+ }, [corePlugin, ...userPlugins]);
28
39
  interaction.init({
29
40
  emitter,
30
41
  editor: this,
@@ -32,10 +43,9 @@ export class Editor {
32
43
  state,
33
44
  interactions: options.interactions,
34
45
  });
35
- this.commander = commander;
36
- this.state = state;
37
- this.plugin = plugin;
38
- this.interaction = interaction;
46
+ }
47
+ registerSync(path, handler, options) {
48
+ return this.syncRegistry.register(path, handler, options);
39
49
  }
40
50
  getDocument() {
41
51
  return this.document;
@@ -46,5 +56,6 @@ export class Editor {
46
56
  this.plugin.destroy();
47
57
  this.commander.destroy();
48
58
  this.state.destroy();
59
+ this.syncRegistry.destroy();
49
60
  }
50
61
  }
@@ -1,3 +1,4 @@
1
+ export * from './commands';
1
2
  export { Editor } from './editor';
2
3
  export * from './interactions';
3
4
  export * from './plugins';
@@ -1,3 +1,4 @@
1
+ export * from './commands/index.js';
1
2
  export { Editor } from './editor.js';
2
3
  export * from './interactions/index.js';
3
4
  export * from './plugins/index.js';
@@ -19,5 +19,4 @@ export declare class BrushSelect extends Interaction implements IInteraction {
19
19
  private clearBrush;
20
20
  private collectSelection;
21
21
  private hasElementAtStart;
22
- private isTextSelectionTarget;
23
22
  }
@@ -8,7 +8,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
8
8
  });
9
9
  };
10
10
  import { createElement, setAttributes } from '../../utils/index.js';
11
- import { clientToViewport, getElementViewportBounds, getEventTarget, getSelectableTarget, } from '../utils/index.js';
11
+ import { clientToViewport, getElementViewportBounds, getEventTarget, getSelectableTarget, isTextSelectionTarget, } from '../utils/index.js';
12
12
  import { Interaction } from './base.js';
13
13
  export class BrushSelect extends Interaction {
14
14
  constructor() {
@@ -22,7 +22,7 @@ export class BrushSelect extends Interaction {
22
22
  return;
23
23
  if (event.button !== 0)
24
24
  return;
25
- if (this.isTextSelectionTarget(event.target))
25
+ if (isTextSelectionTarget(event.target))
26
26
  return;
27
27
  if (this.hasElementAtStart(event.target))
28
28
  return;
@@ -170,12 +170,4 @@ export class BrushSelect extends Interaction {
170
170
  return true;
171
171
  return Boolean((_a = target.closest) === null || _a === void 0 ? void 0 : _a.call(target, '[data-element-type]'));
172
172
  }
173
- isTextSelectionTarget(target) {
174
- if (!(target instanceof HTMLElement))
175
- return false;
176
- if (target.isContentEditable)
177
- return true;
178
- const tag = target.tagName.toLowerCase();
179
- return tag === 'input' || tag === 'textarea';
180
- }
181
173
  }
@@ -0,0 +1,35 @@
1
+ import { IInteraction, InteractionInitOptions, KeyCode } from '../types';
2
+ import { Interaction } from './base';
3
+ export interface DragCanvasOptions {
4
+ trigger?: KeyCode[];
5
+ }
6
+ export declare class DragCanvas extends Interaction implements IInteraction {
7
+ name: string;
8
+ /**
9
+ * 触发交互的按键代码。
10
+ * 参考标准的 KeyboardEvent.code 值:
11
+ * https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/code/code_values
12
+ * @default ['Space']
13
+ */
14
+ trigger: KeyCode[];
15
+ constructor(options?: DragCanvasOptions);
16
+ private isTriggerPressed;
17
+ private pointerId?;
18
+ private startPoint?;
19
+ private document;
20
+ private startViewBoxString?;
21
+ private completeInteraction?;
22
+ private isHovering;
23
+ init(options: InteractionInitOptions): void;
24
+ destroy(): void;
25
+ private handleKeyDown;
26
+ private handlePointerDown;
27
+ private handlePointerMove;
28
+ private handlePointerUp;
29
+ private handleKeyUp;
30
+ private stopDrag;
31
+ private setCursor;
32
+ private handleBlur;
33
+ private onMouseEnter;
34
+ private onMouseLeave;
35
+ }
@@ -0,0 +1,161 @@
1
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
2
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
3
+ return new (P || (P = Promise))(function (resolve, reject) {
4
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
5
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
6
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
7
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
8
+ });
9
+ };
10
+ import { getViewBox, viewBoxToString } from '../../utils/index.js';
11
+ import { UpdateOptionsCommand } from '../commands/index.js';
12
+ import { clientToViewport, isTextSelectionTarget } from '../utils/index.js';
13
+ import { Interaction } from './base.js';
14
+ export class DragCanvas extends Interaction {
15
+ constructor(options) {
16
+ super();
17
+ this.name = 'drag-canvas';
18
+ /**
19
+ * 触发交互的按键代码。
20
+ * 参考标准的 KeyboardEvent.code 值:
21
+ * https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/code/code_values
22
+ * @default ['Space']
23
+ */
24
+ this.trigger = ['Space'];
25
+ this.isTriggerPressed = false;
26
+ // 防止组件快捷键侵入性过强
27
+ this.isHovering = false;
28
+ this.handleKeyDown = (event) => {
29
+ if (!this.interaction.isActive())
30
+ return;
31
+ if (isTextSelectionTarget(event.target))
32
+ return;
33
+ // 增加焦点的判断,防止对空格的preventDefault侵入性过强
34
+ const target = event.target;
35
+ const isBody = target === document.body || target === document.documentElement;
36
+ const isEditor = target === this.document || this.document.contains(target);
37
+ if (!isBody && !isEditor)
38
+ return;
39
+ if (!this.trigger.includes(event.code))
40
+ return;
41
+ if (!this.isHovering && !this.isTriggerPressed)
42
+ return;
43
+ event.preventDefault();
44
+ event.stopPropagation();
45
+ this.interaction.executeExclusiveInteraction(this, () => __awaiter(this, void 0, void 0, function* () {
46
+ return new Promise((resolve) => {
47
+ this.completeInteraction = resolve;
48
+ this.isTriggerPressed = true;
49
+ const viewBox = getViewBox(this.document);
50
+ this.startViewBoxString = viewBoxToString(viewBox);
51
+ this.setCursor('grab');
52
+ this.document.addEventListener('pointerdown', this.handlePointerDown);
53
+ window.addEventListener('keyup', this.handleKeyUp);
54
+ });
55
+ }));
56
+ };
57
+ this.handlePointerDown = (event) => {
58
+ if (event.button !== 0)
59
+ return;
60
+ event.preventDefault();
61
+ event.stopPropagation();
62
+ const svg = this.document;
63
+ this.startPoint = clientToViewport(svg, event.clientX, event.clientY);
64
+ this.pointerId = event.pointerId;
65
+ this.setCursor('grabbing');
66
+ window.addEventListener('pointermove', this.handlePointerMove);
67
+ window.addEventListener('pointerup', this.handlePointerUp);
68
+ window.addEventListener('pointercancel', this.handlePointerUp);
69
+ };
70
+ this.handlePointerMove = (event) => {
71
+ if (event.pointerId !== this.pointerId || !this.startPoint)
72
+ return;
73
+ event.preventDefault();
74
+ event.stopPropagation();
75
+ const svg = this.document;
76
+ const current = clientToViewport(svg, event.clientX, event.clientY);
77
+ const dx = current.x - this.startPoint.x;
78
+ const dy = current.y - this.startPoint.y;
79
+ const viewBox = getViewBox(svg);
80
+ const { x, y, width, height } = viewBox;
81
+ const newX = x - dx;
82
+ const newY = y - dy;
83
+ this.state.updateOptions({
84
+ viewBox: viewBoxToString({ x: newX, y: newY, width, height }),
85
+ });
86
+ };
87
+ this.handlePointerUp = (event) => {
88
+ if (event.pointerId !== this.pointerId)
89
+ return;
90
+ this.startPoint = undefined;
91
+ this.pointerId = undefined;
92
+ this.setCursor('grab');
93
+ window.removeEventListener('pointermove', this.handlePointerMove);
94
+ window.removeEventListener('pointerup', this.handlePointerUp);
95
+ window.removeEventListener('pointercancel', this.handlePointerUp);
96
+ };
97
+ this.handleKeyUp = (event) => {
98
+ if (!this.trigger.includes(event.code))
99
+ return;
100
+ this.stopDrag();
101
+ };
102
+ this.stopDrag = () => {
103
+ var _a;
104
+ if (this.startViewBoxString) {
105
+ const svg = this.document;
106
+ const viewBox = getViewBox(svg);
107
+ const currentViewBoxString = viewBoxToString(viewBox);
108
+ if (this.startViewBoxString !== currentViewBoxString) {
109
+ const command = new UpdateOptionsCommand({ viewBox: currentViewBoxString }, { viewBox: this.startViewBoxString });
110
+ void this.commander.execute(command);
111
+ }
112
+ }
113
+ this.startViewBoxString = undefined;
114
+ this.isTriggerPressed = false;
115
+ this.setCursor('default');
116
+ this.startPoint = undefined;
117
+ this.pointerId = undefined;
118
+ window.removeEventListener('keyup', this.handleKeyUp);
119
+ this.document.removeEventListener('pointerdown', this.handlePointerDown);
120
+ window.removeEventListener('pointermove', this.handlePointerMove);
121
+ window.removeEventListener('pointerup', this.handlePointerUp);
122
+ window.removeEventListener('pointercancel', this.handlePointerUp);
123
+ (_a = this.completeInteraction) === null || _a === void 0 ? void 0 : _a.call(this);
124
+ this.completeInteraction = undefined;
125
+ };
126
+ this.setCursor = (behavior) => {
127
+ document.body.style.cursor = behavior;
128
+ };
129
+ this.handleBlur = () => {
130
+ this.stopDrag();
131
+ };
132
+ this.onMouseEnter = () => {
133
+ this.isHovering = true;
134
+ };
135
+ this.onMouseLeave = () => {
136
+ this.isHovering = false;
137
+ };
138
+ if (options === null || options === void 0 ? void 0 : options.trigger) {
139
+ this.trigger = options.trigger;
140
+ }
141
+ }
142
+ init(options) {
143
+ super.init(options);
144
+ this.document = this.editor.getDocument();
145
+ this.document.addEventListener('mouseenter', this.onMouseEnter);
146
+ this.document.addEventListener('mouseleave', this.onMouseLeave);
147
+ window.addEventListener('keydown', this.handleKeyDown);
148
+ window.addEventListener('blur', this.handleBlur);
149
+ }
150
+ destroy() {
151
+ window.removeEventListener('keydown', this.handleKeyDown);
152
+ window.removeEventListener('keyup', this.handleKeyUp);
153
+ this.document.removeEventListener('pointerdown', this.handlePointerDown);
154
+ window.removeEventListener('pointermove', this.handlePointerMove);
155
+ window.removeEventListener('pointerup', this.handlePointerUp);
156
+ window.removeEventListener('pointercancel', this.handlePointerUp);
157
+ window.removeEventListener('blur', this.handleBlur);
158
+ this.document.removeEventListener('mouseenter', this.onMouseEnter);
159
+ this.document.removeEventListener('mouseleave', this.onMouseLeave);
160
+ }
161
+ }
@@ -113,9 +113,6 @@ export class DragElement extends Interaction {
113
113
  return true;
114
114
  if (!this.startTarget)
115
115
  return false;
116
- if (this.willReplaceSelection) {
117
- this.interaction.select([this.startTarget], 'replace');
118
- }
119
116
  this.dragItems = this.selectionForDrag
120
117
  .filter((element) => isEditableText(element))
121
118
  .map((element) => this.createDragItem(element))
@@ -125,6 +122,10 @@ export class DragElement extends Interaction {
125
122
  let started = false;
126
123
  this.interaction.executeExclusiveInteraction(this, () => __awaiter(this, void 0, void 0, function* () {
127
124
  return new Promise((resolve) => {
125
+ // 只有拿到锁之后,才真正执行选中逻辑
126
+ if (this.willReplaceSelection && this.startTarget) {
127
+ this.interaction.select([this.startTarget], 'replace');
128
+ }
128
129
  this.completeInteraction = resolve;
129
130
  started = true;
130
131
  });
@@ -2,6 +2,7 @@ export { Interaction } from './base';
2
2
  export { BrushSelect } from './brush-select';
3
3
  export { ClickSelect } from './click-select';
4
4
  export { DblClickEditText } from './dblclick-edit-text';
5
+ export { DragCanvas } from './drag-canvas';
5
6
  export { DragElement } from './drag-element';
6
7
  export { HotkeyHistory } from './hotkey-history';
7
8
  export { SelectHighlight } from './select-highlight';
@@ -2,6 +2,7 @@ export { Interaction } from './base.js';
2
2
  export { BrushSelect } from './brush-select.js';
3
3
  export { ClickSelect } from './click-select.js';
4
4
  export { DblClickEditText } from './dblclick-edit-text.js';
5
+ export { DragCanvas } from './drag-canvas.js';
5
6
  export { DragElement } from './drag-element.js';
6
7
  export { HotkeyHistory } from './hotkey-history.js';
7
8
  export { SelectHighlight } from './select-highlight.js';