@antv/infographic 0.2.13 → 0.2.14

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 (186) hide show
  1. package/dist/infographic.min.js +123 -116
  2. package/dist/infographic.min.js.map +1 -1
  3. package/esm/editor/commands/UpdateOptions.d.ts +4 -4
  4. package/esm/editor/commands/UpdateOptions.js +6 -3
  5. package/esm/editor/editor.d.ts +5 -1
  6. package/esm/editor/editor.js +16 -5
  7. package/esm/editor/index.d.ts +1 -0
  8. package/esm/editor/index.js +1 -0
  9. package/esm/editor/interactions/brush-select.d.ts +0 -1
  10. package/esm/editor/interactions/brush-select.js +2 -10
  11. package/esm/editor/interactions/drag-canvas.d.ts +35 -0
  12. package/esm/editor/interactions/drag-canvas.js +161 -0
  13. package/esm/editor/interactions/drag-element.js +4 -3
  14. package/esm/editor/interactions/index.d.ts +1 -0
  15. package/esm/editor/interactions/index.js +1 -0
  16. package/esm/editor/interactions/zoom-wheel.d.ts +9 -0
  17. package/esm/editor/interactions/zoom-wheel.js +32 -15
  18. package/esm/editor/managers/index.d.ts +1 -0
  19. package/esm/editor/managers/index.js +1 -0
  20. package/esm/editor/managers/state.d.ts +4 -2
  21. package/esm/editor/managers/state.js +14 -13
  22. package/esm/editor/managers/sync-registry.d.ts +15 -0
  23. package/esm/editor/managers/sync-registry.js +51 -0
  24. package/esm/editor/plugins/{edit-bar/components → components}/button.js +1 -1
  25. package/esm/editor/plugins/{edit-bar/components → components}/color-picker.js +1 -1
  26. package/esm/editor/plugins/{edit-bar/components → components}/icons.d.ts +1 -0
  27. package/esm/editor/plugins/{edit-bar/components → components}/icons.js +1 -0
  28. package/esm/editor/plugins/{edit-bar/components → components}/popover.js +2 -2
  29. package/esm/editor/plugins/{edit-bar/components → components}/select.js +1 -1
  30. package/esm/editor/plugins/core-sync.d.ts +8 -0
  31. package/esm/editor/plugins/core-sync.js +30 -0
  32. package/esm/editor/plugins/edit-bar/edit-items/align-elements.js +1 -1
  33. package/esm/editor/plugins/edit-bar/edit-items/font-align.js +1 -1
  34. package/esm/editor/plugins/edit-bar/edit-items/font-color.js +1 -1
  35. package/esm/editor/plugins/edit-bar/edit-items/font-family.js +1 -1
  36. package/esm/editor/plugins/edit-bar/edit-items/font-size.js +1 -1
  37. package/esm/editor/plugins/edit-bar/edit-items/icon-color.js +1 -1
  38. package/esm/editor/plugins/edit-bar/index.d.ts +2 -2
  39. package/esm/editor/plugins/edit-bar/index.js +1 -1
  40. package/esm/editor/plugins/index.d.ts +2 -0
  41. package/esm/editor/plugins/index.js +2 -0
  42. package/esm/editor/plugins/reset-viewbox.d.ts +33 -0
  43. package/esm/editor/plugins/reset-viewbox.js +186 -0
  44. package/esm/editor/types/editor.d.ts +13 -0
  45. package/esm/editor/types/index.d.ts +1 -0
  46. package/esm/editor/types/interaction.d.ts +9 -0
  47. package/esm/editor/types/state.d.ts +4 -2
  48. package/esm/editor/types/sync.d.ts +26 -0
  49. package/esm/editor/types/sync.js +1 -0
  50. package/esm/editor/utils/data.js +3 -1
  51. package/esm/editor/utils/event.d.ts +1 -0
  52. package/esm/editor/utils/event.js +8 -0
  53. package/esm/editor/utils/index.d.ts +1 -0
  54. package/esm/editor/utils/index.js +1 -0
  55. package/esm/editor/utils/object.d.ts +15 -0
  56. package/esm/editor/utils/object.js +70 -0
  57. package/esm/index.d.ts +4 -3
  58. package/esm/index.js +3 -2
  59. package/esm/options/types.d.ts +1 -0
  60. package/esm/runtime/options.js +7 -2
  61. package/esm/templates/built-in.js +24 -0
  62. package/esm/utils/measure-text.js +9 -6
  63. package/esm/utils/padding.d.ts +1 -0
  64. package/esm/utils/padding.js +6 -2
  65. package/esm/version.d.ts +1 -1
  66. package/esm/version.js +1 -1
  67. package/lib/editor/commands/UpdateOptions.d.ts +4 -4
  68. package/lib/editor/commands/UpdateOptions.js +6 -3
  69. package/lib/editor/editor.d.ts +5 -1
  70. package/lib/editor/editor.js +16 -5
  71. package/lib/editor/index.d.ts +1 -0
  72. package/lib/editor/index.js +1 -0
  73. package/lib/editor/interactions/brush-select.d.ts +0 -1
  74. package/lib/editor/interactions/brush-select.js +1 -9
  75. package/lib/editor/interactions/drag-canvas.d.ts +35 -0
  76. package/lib/editor/interactions/drag-canvas.js +165 -0
  77. package/lib/editor/interactions/drag-element.js +4 -3
  78. package/lib/editor/interactions/index.d.ts +1 -0
  79. package/lib/editor/interactions/index.js +3 -1
  80. package/lib/editor/interactions/zoom-wheel.d.ts +9 -0
  81. package/lib/editor/interactions/zoom-wheel.js +32 -15
  82. package/lib/editor/managers/index.d.ts +1 -0
  83. package/lib/editor/managers/index.js +1 -0
  84. package/lib/editor/managers/state.d.ts +4 -2
  85. package/lib/editor/managers/state.js +12 -11
  86. package/lib/editor/managers/sync-registry.d.ts +15 -0
  87. package/lib/editor/managers/sync-registry.js +55 -0
  88. package/lib/editor/plugins/{edit-bar/components → components}/button.js +1 -1
  89. package/lib/editor/plugins/{edit-bar/components → components}/color-picker.js +1 -1
  90. package/lib/editor/plugins/{edit-bar/components → components}/icons.d.ts +1 -0
  91. package/lib/editor/plugins/{edit-bar/components → components}/icons.js +2 -1
  92. package/lib/editor/plugins/{edit-bar/components → components}/popover.js +2 -2
  93. package/lib/editor/plugins/{edit-bar/components → components}/select.js +1 -1
  94. package/lib/editor/plugins/core-sync.d.ts +8 -0
  95. package/lib/editor/plugins/core-sync.js +34 -0
  96. package/lib/editor/plugins/edit-bar/edit-items/align-elements.js +1 -1
  97. package/lib/editor/plugins/edit-bar/edit-items/font-align.js +1 -1
  98. package/lib/editor/plugins/edit-bar/edit-items/font-color.js +1 -1
  99. package/lib/editor/plugins/edit-bar/edit-items/font-family.js +1 -1
  100. package/lib/editor/plugins/edit-bar/edit-items/font-size.js +1 -1
  101. package/lib/editor/plugins/edit-bar/edit-items/icon-color.js +1 -1
  102. package/lib/editor/plugins/edit-bar/index.d.ts +2 -2
  103. package/lib/editor/plugins/edit-bar/index.js +1 -1
  104. package/lib/editor/plugins/index.d.ts +2 -0
  105. package/lib/editor/plugins/index.js +5 -1
  106. package/lib/editor/plugins/reset-viewbox.d.ts +33 -0
  107. package/lib/editor/plugins/reset-viewbox.js +190 -0
  108. package/lib/editor/types/editor.d.ts +13 -0
  109. package/lib/editor/types/index.d.ts +1 -0
  110. package/lib/editor/types/interaction.d.ts +9 -0
  111. package/lib/editor/types/state.d.ts +4 -2
  112. package/lib/editor/types/sync.d.ts +26 -0
  113. package/lib/editor/types/sync.js +2 -0
  114. package/lib/editor/utils/data.js +3 -1
  115. package/lib/editor/utils/event.d.ts +1 -0
  116. package/lib/editor/utils/event.js +9 -0
  117. package/lib/editor/utils/index.d.ts +1 -0
  118. package/lib/editor/utils/index.js +1 -0
  119. package/lib/editor/utils/object.d.ts +15 -0
  120. package/lib/editor/utils/object.js +73 -0
  121. package/lib/index.d.ts +4 -3
  122. package/lib/index.js +9 -2
  123. package/lib/options/types.d.ts +1 -0
  124. package/lib/runtime/options.js +6 -1
  125. package/lib/templates/built-in.js +24 -0
  126. package/lib/utils/measure-text.js +9 -6
  127. package/lib/utils/padding.d.ts +1 -0
  128. package/lib/utils/padding.js +7 -2
  129. package/lib/version.d.ts +1 -1
  130. package/lib/version.js +1 -1
  131. package/package.json +1 -1
  132. package/src/editor/commands/UpdateOptions.ts +11 -6
  133. package/src/editor/editor.ts +26 -5
  134. package/src/editor/index.ts +1 -0
  135. package/src/editor/interactions/brush-select.ts +2 -8
  136. package/src/editor/interactions/drag-canvas.ts +203 -0
  137. package/src/editor/interactions/drag-element.ts +5 -4
  138. package/src/editor/interactions/index.ts +1 -0
  139. package/src/editor/interactions/zoom-wheel.ts +49 -13
  140. package/src/editor/managers/index.ts +1 -0
  141. package/src/editor/managers/state.ts +21 -21
  142. package/src/editor/managers/sync-registry.ts +65 -0
  143. package/src/editor/plugins/{edit-bar/components → components}/button.ts +1 -1
  144. package/src/editor/plugins/{edit-bar/components → components}/color-picker.ts +1 -1
  145. package/src/editor/plugins/{edit-bar/components → components}/icons.ts +4 -0
  146. package/src/editor/plugins/{edit-bar/components → components}/popover.ts +2 -2
  147. package/src/editor/plugins/{edit-bar/components → components}/select.ts +1 -1
  148. package/src/editor/plugins/core-sync.ts +44 -0
  149. package/src/editor/plugins/edit-bar/edit-items/align-elements.ts +2 -2
  150. package/src/editor/plugins/edit-bar/edit-items/font-align.ts +1 -1
  151. package/src/editor/plugins/edit-bar/edit-items/font-color.ts +1 -1
  152. package/src/editor/plugins/edit-bar/edit-items/font-family.ts +1 -1
  153. package/src/editor/plugins/edit-bar/edit-items/font-size.ts +3 -3
  154. package/src/editor/plugins/edit-bar/edit-items/icon-color.ts +1 -1
  155. package/src/editor/plugins/edit-bar/index.ts +2 -2
  156. package/src/editor/plugins/index.ts +2 -0
  157. package/src/editor/plugins/reset-viewbox.ts +258 -0
  158. package/src/editor/types/editor.ts +17 -0
  159. package/src/editor/types/index.ts +1 -0
  160. package/src/editor/types/interaction.ts +31 -0
  161. package/src/editor/types/state.ts +14 -2
  162. package/src/editor/types/sync.ts +31 -0
  163. package/src/editor/utils/data.ts +2 -1
  164. package/src/editor/utils/event.ts +7 -0
  165. package/src/editor/utils/index.ts +1 -0
  166. package/src/editor/utils/object.ts +106 -0
  167. package/src/index.ts +26 -2
  168. package/src/options/types.ts +4 -0
  169. package/src/runtime/options.ts +8 -1
  170. package/src/templates/built-in.ts +28 -0
  171. package/src/utils/measure-text.ts +6 -6
  172. package/src/utils/padding.ts +10 -2
  173. package/src/version.ts +1 -1
  174. /package/esm/editor/plugins/{edit-bar/components → components}/button.d.ts +0 -0
  175. /package/esm/editor/plugins/{edit-bar/components → components}/color-picker.d.ts +0 -0
  176. /package/esm/editor/plugins/{edit-bar/components → components}/index.d.ts +0 -0
  177. /package/esm/editor/plugins/{edit-bar/components → components}/index.js +0 -0
  178. /package/esm/editor/plugins/{edit-bar/components → components}/popover.d.ts +0 -0
  179. /package/esm/editor/plugins/{edit-bar/components → components}/select.d.ts +0 -0
  180. /package/lib/editor/plugins/{edit-bar/components → components}/button.d.ts +0 -0
  181. /package/lib/editor/plugins/{edit-bar/components → components}/color-picker.d.ts +0 -0
  182. /package/lib/editor/plugins/{edit-bar/components → components}/index.d.ts +0 -0
  183. /package/lib/editor/plugins/{edit-bar/components → components}/index.js +0 -0
  184. /package/lib/editor/plugins/{edit-bar/components → components}/popover.d.ts +0 -0
  185. /package/lib/editor/plugins/{edit-bar/components → components}/select.d.ts +0 -0
  186. /package/src/editor/plugins/{edit-bar/components → components}/index.ts +0 -0
@@ -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';
@@ -1,7 +1,16 @@
1
1
  import type { IInteraction, InteractionInitOptions } from '../types';
2
2
  import { Interaction } from './base';
3
+ export interface ZoomWheelOptions {
4
+ minViewBoxSize?: number;
5
+ maxViewBoxSize?: number;
6
+ }
3
7
  export declare class ZoomWheel extends Interaction implements IInteraction {
4
8
  name: string;
9
+ private minViewBoxSize;
10
+ private maxViewBoxSize;
11
+ constructor(options?: ZoomWheelOptions);
12
+ private initialViewBox;
13
+ private handleKeyUp;
5
14
  private wheelListener;
6
15
  private getMousePoint;
7
16
  private getCenterPoint;
@@ -3,13 +3,26 @@ import { calculateZoomedViewBox, getViewBox, viewBoxToString, } from '../../util
3
3
  import { UpdateOptionsCommand } from '../commands/index.js';
4
4
  import { clientToViewport } from '../utils/index.js';
5
5
  import { Interaction } from './base.js';
6
- const MIN_VIEWBOX_SIZE = 20;
7
- const MAX_VIEWBOX_SIZE = 2000;
8
6
  const ZOOM_FACTOR = 1.1;
9
7
  export class ZoomWheel extends Interaction {
10
- constructor() {
11
- super(...arguments);
8
+ constructor(options) {
9
+ super();
12
10
  this.name = 'zoom-wheel';
11
+ this.minViewBoxSize = 20;
12
+ this.maxViewBoxSize = 20000;
13
+ this.initialViewBox = null;
14
+ this.handleKeyUp = (event) => {
15
+ const isZoomModifierHeld = event.ctrlKey || event.metaKey || event.shiftKey;
16
+ if (!isZoomModifierHeld && this.initialViewBox) {
17
+ const currentViewBox = viewBoxToString(getViewBox(this.editor.getDocument()));
18
+ if (currentViewBox !== this.initialViewBox) {
19
+ const command = new UpdateOptionsCommand({ viewBox: currentViewBox }, { viewBox: this.initialViewBox });
20
+ void this.commander.execute(command);
21
+ }
22
+ this.initialViewBox = null;
23
+ document.removeEventListener('keyup', this.handleKeyUp);
24
+ }
25
+ };
13
26
  this.wheelListener = (event) => {
14
27
  if (!this.shouldZoom(event))
15
28
  return;
@@ -22,25 +35,20 @@ export class ZoomWheel extends Interaction {
22
35
  const { width, height } = viewBox;
23
36
  const newWidth = width * factor;
24
37
  const newHeight = height * factor;
25
- if (!inRange(newWidth, MIN_VIEWBOX_SIZE, MAX_VIEWBOX_SIZE) ||
26
- !inRange(newHeight, MIN_VIEWBOX_SIZE, MAX_VIEWBOX_SIZE))
27
- return;
28
- // TODO: Remove after implementing the reset UI plugin
29
- if ((event.ctrlKey || event.metaKey) && event.shiftKey) {
30
- const command = new UpdateOptionsCommand({
31
- viewBox: undefined,
32
- });
33
- void this.commander.execute(command);
38
+ if (!inRange(newWidth, this.minViewBoxSize, this.maxViewBoxSize) ||
39
+ !inRange(newHeight, this.minViewBoxSize, this.maxViewBoxSize))
34
40
  return;
41
+ if (this.initialViewBox === null) {
42
+ this.initialViewBox = viewBoxToString(viewBox);
43
+ document.addEventListener('keyup', this.handleKeyUp);
35
44
  }
36
45
  const pivot = (event.ctrlKey || event.metaKey) && !event.shiftKey
37
46
  ? this.getMousePoint(svg, event)
38
47
  : this.getCenterPoint(viewBox);
39
48
  const newViewBox = calculateZoomedViewBox(viewBox, factor, pivot);
40
- const command = new UpdateOptionsCommand({
49
+ this.state.updateOptions({
41
50
  viewBox: viewBoxToString(newViewBox),
42
51
  });
43
- void this.commander.execute(command);
44
52
  };
45
53
  this.getMousePoint = (svg, event) => {
46
54
  return clientToViewport(svg, event.clientX, event.clientY);
@@ -57,8 +65,16 @@ export class ZoomWheel extends Interaction {
57
65
  return false;
58
66
  const isMouseZoom = event.ctrlKey || event.metaKey;
59
67
  const isCenterZoom = event.shiftKey;
68
+ if (isMouseZoom && isCenterZoom)
69
+ return false;
60
70
  return isMouseZoom || isCenterZoom;
61
71
  };
72
+ if ((options === null || options === void 0 ? void 0 : options.minViewBoxSize) !== undefined) {
73
+ this.minViewBoxSize = options.minViewBoxSize;
74
+ }
75
+ if ((options === null || options === void 0 ? void 0 : options.maxViewBoxSize) !== undefined) {
76
+ this.maxViewBoxSize = options.maxViewBoxSize;
77
+ }
62
78
  }
63
79
  init(options) {
64
80
  super.init(options);
@@ -66,5 +82,6 @@ export class ZoomWheel extends Interaction {
66
82
  }
67
83
  destroy() {
68
84
  document.removeEventListener('wheel', this.wheelListener);
85
+ document.removeEventListener('keyup', this.handleKeyUp);
69
86
  }
70
87
  }
@@ -2,3 +2,4 @@ export * from './command';
2
2
  export * from './interaction';
3
3
  export * from './plugin';
4
4
  export * from './state';
5
+ export * from './sync-registry';
@@ -2,3 +2,4 @@ export * from './command.js';
2
2
  export * from './interaction.js';
3
3
  export * from './plugin.js';
4
4
  export * from './state.js';
5
+ export * from './sync-registry.js';
@@ -1,4 +1,4 @@
1
- import type { ParsedInfographicOptions } from '../../options';
1
+ import type { ParsedInfographicOptions, UpdatableInfographicOptions } from '../../options';
2
2
  import type { Element, IEventEmitter, ItemDatum } from '../../types';
3
3
  import type { ElementProps, ICommandManager, IEditor, IStateManager, StateManagerInitOptions } from '../types';
4
4
  export declare class StateManager implements IStateManager {
@@ -12,7 +12,9 @@ export declare class StateManager implements IStateManager {
12
12
  removeItemDatum(indexes: number[], count?: number): void;
13
13
  updateData(key: string, value: any): void;
14
14
  updateElement(element: Element, props: Partial<ElementProps>): void;
15
- updateOptions(options: ParsedInfographicOptions): void;
15
+ updateOptions(options: UpdatableInfographicOptions, execOptions?: {
16
+ bubbleUp?: boolean;
17
+ }): void;
16
18
  getOptions(): ParsedInfographicOptions;
17
19
  /**
18
20
  * 不包含文本内容、图标类型更新
@@ -1,5 +1,5 @@
1
- import { getDatumByIndexes, getElementRole, isIconElement, parsePadding, setSVGPadding, } from '../../utils/index.js';
2
- import { buildItemPath, getChildrenDataByIndexes, getIndexesFromElement, } from '../utils/index.js';
1
+ import { getDatumByIndexes, getElementRole, isIconElement } from '../../utils/index.js';
2
+ import { applyOptionUpdates, buildItemPath, getChildrenDataByIndexes, getIndexesFromElement, } from '../utils/index.js';
3
3
  export class StateManager {
4
4
  init(options) {
5
5
  Object.assign(this, options);
@@ -25,6 +25,8 @@ export class StateManager {
25
25
  }
26
26
  updateItemDatum(indexes, datum) {
27
27
  const item = getDatumByIndexes(this.options.data, indexes);
28
+ if (item == null || indexes.length === 0)
29
+ return;
28
30
  Object.assign(item, datum);
29
31
  this.emitter.emit('options:data:item:update', { indexes, datum });
30
32
  this.emitter.emit('options:change', {
@@ -74,17 +76,14 @@ export class StateManager {
74
76
  updateElement(element, props) {
75
77
  this.updateBuiltInElement(element, props);
76
78
  }
77
- updateOptions(options) {
78
- this.options = Object.assign(Object.assign({}, this.options), options);
79
- if (this.options.viewBox) {
80
- this.editor.getDocument().setAttribute('viewBox', this.options.viewBox);
81
- }
82
- else {
83
- this.editor.getDocument().removeAttribute('viewBox');
84
- if (this.options.padding !== undefined) {
85
- setSVGPadding(this.editor.getDocument(), parsePadding(this.options.padding));
86
- }
87
- }
79
+ updateOptions(options, execOptions) {
80
+ const { bubbleUp = false } = execOptions || {};
81
+ applyOptionUpdates(this.options, options, '', {
82
+ bubbleUp,
83
+ collector: (path, newVal, oldVal) => {
84
+ this.editor.syncRegistry.trigger(path, newVal, oldVal);
85
+ },
86
+ });
88
87
  this.emitter.emit('options:change', {
89
88
  type: 'options:change',
90
89
  changes: [
@@ -115,6 +114,8 @@ export class StateManager {
115
114
  const indexes = isItemElement ? getIndexesFromElement(element) : undefined;
116
115
  if (isItemElement) {
117
116
  const datum = getDatumByIndexes(data, indexes);
117
+ if (datum == null)
118
+ return;
118
119
  const key = role.replace('item-', '');
119
120
  datum.attributes || (datum.attributes = {});
120
121
  (_a = datum.attributes)[key] || (_a[key] = {});
@@ -0,0 +1,15 @@
1
+ import { ISyncRegistry, SyncHandler } from '../types';
2
+ type OptionsGetter = () => any;
3
+ export declare class SyncRegistry implements ISyncRegistry {
4
+ private getOptions;
5
+ private handlers;
6
+ private isDispatching;
7
+ private isDestroyed;
8
+ constructor(getOptions: OptionsGetter);
9
+ register(path: string, handler: SyncHandler, options?: {
10
+ immediate?: boolean;
11
+ }): () => void;
12
+ trigger(path: string, newVal: any, oldVal: any): void;
13
+ destroy(): void;
14
+ }
15
+ export {};
@@ -0,0 +1,51 @@
1
+ import { get } from 'lodash-es';
2
+ export class SyncRegistry {
3
+ constructor(getOptions) {
4
+ this.getOptions = getOptions;
5
+ this.handlers = new Map();
6
+ // lock to prevent recursive updates
7
+ this.isDispatching = false;
8
+ this.isDestroyed = false;
9
+ }
10
+ register(path, handler, options) {
11
+ if (!this.handlers.has(path)) {
12
+ this.handlers.set(path, new Set());
13
+ }
14
+ this.handlers.get(path).add(handler);
15
+ if (options === null || options === void 0 ? void 0 : options.immediate) {
16
+ const currentVal = get(this.getOptions(), path);
17
+ handler(currentVal, undefined);
18
+ }
19
+ return () => {
20
+ const set = this.handlers.get(path);
21
+ if (set) {
22
+ set.delete(handler);
23
+ if (set.size === 0) {
24
+ this.handlers.delete(path);
25
+ }
26
+ }
27
+ };
28
+ }
29
+ trigger(path, newVal, oldVal) {
30
+ if (this.isDestroyed || this.isDispatching) {
31
+ if (this.isDispatching) {
32
+ console.warn(`[SyncRegistry] Recursive update detected on ${path}. Skipped to prevent loop.`);
33
+ }
34
+ return;
35
+ }
36
+ const handlers = this.handlers.get(path);
37
+ if (handlers) {
38
+ this.isDispatching = true;
39
+ try {
40
+ handlers.forEach((fn) => fn(newVal, oldVal));
41
+ }
42
+ finally {
43
+ this.isDispatching = false;
44
+ }
45
+ }
46
+ }
47
+ destroy() {
48
+ this.isDestroyed = true;
49
+ this.handlers.clear();
50
+ }
51
+ }