@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.
- package/dist/infographic.min.js +123 -116
- package/dist/infographic.min.js.map +1 -1
- package/esm/editor/commands/UpdateOptions.d.ts +4 -4
- package/esm/editor/commands/UpdateOptions.js +6 -3
- package/esm/editor/editor.d.ts +5 -1
- package/esm/editor/editor.js +16 -5
- package/esm/editor/index.d.ts +1 -0
- package/esm/editor/index.js +1 -0
- package/esm/editor/interactions/brush-select.d.ts +0 -1
- package/esm/editor/interactions/brush-select.js +2 -10
- package/esm/editor/interactions/drag-canvas.d.ts +35 -0
- package/esm/editor/interactions/drag-canvas.js +161 -0
- package/esm/editor/interactions/drag-element.js +4 -3
- package/esm/editor/interactions/index.d.ts +1 -0
- package/esm/editor/interactions/index.js +1 -0
- package/esm/editor/interactions/zoom-wheel.d.ts +9 -0
- package/esm/editor/interactions/zoom-wheel.js +32 -15
- package/esm/editor/managers/index.d.ts +1 -0
- package/esm/editor/managers/index.js +1 -0
- package/esm/editor/managers/state.d.ts +4 -2
- package/esm/editor/managers/state.js +14 -13
- package/esm/editor/managers/sync-registry.d.ts +15 -0
- package/esm/editor/managers/sync-registry.js +51 -0
- package/esm/editor/plugins/{edit-bar/components → components}/button.js +1 -1
- package/esm/editor/plugins/{edit-bar/components → components}/color-picker.js +1 -1
- package/esm/editor/plugins/{edit-bar/components → components}/icons.d.ts +1 -0
- package/esm/editor/plugins/{edit-bar/components → components}/icons.js +1 -0
- package/esm/editor/plugins/{edit-bar/components → components}/popover.js +2 -2
- package/esm/editor/plugins/{edit-bar/components → components}/select.js +1 -1
- package/esm/editor/plugins/core-sync.d.ts +8 -0
- package/esm/editor/plugins/core-sync.js +30 -0
- package/esm/editor/plugins/edit-bar/edit-items/align-elements.js +1 -1
- package/esm/editor/plugins/edit-bar/edit-items/font-align.js +1 -1
- package/esm/editor/plugins/edit-bar/edit-items/font-color.js +1 -1
- package/esm/editor/plugins/edit-bar/edit-items/font-family.js +1 -1
- package/esm/editor/plugins/edit-bar/edit-items/font-size.js +1 -1
- package/esm/editor/plugins/edit-bar/edit-items/icon-color.js +1 -1
- package/esm/editor/plugins/edit-bar/index.d.ts +2 -2
- package/esm/editor/plugins/edit-bar/index.js +1 -1
- package/esm/editor/plugins/index.d.ts +2 -0
- package/esm/editor/plugins/index.js +2 -0
- package/esm/editor/plugins/reset-viewbox.d.ts +33 -0
- package/esm/editor/plugins/reset-viewbox.js +186 -0
- package/esm/editor/types/editor.d.ts +13 -0
- package/esm/editor/types/index.d.ts +1 -0
- package/esm/editor/types/interaction.d.ts +9 -0
- package/esm/editor/types/state.d.ts +4 -2
- package/esm/editor/types/sync.d.ts +26 -0
- package/esm/editor/types/sync.js +1 -0
- package/esm/editor/utils/data.js +3 -1
- package/esm/editor/utils/event.d.ts +1 -0
- package/esm/editor/utils/event.js +8 -0
- package/esm/editor/utils/index.d.ts +1 -0
- package/esm/editor/utils/index.js +1 -0
- package/esm/editor/utils/object.d.ts +15 -0
- package/esm/editor/utils/object.js +70 -0
- package/esm/index.d.ts +4 -3
- package/esm/index.js +3 -2
- package/esm/options/types.d.ts +1 -0
- package/esm/runtime/options.js +7 -2
- package/esm/templates/built-in.js +24 -0
- package/esm/utils/measure-text.js +9 -6
- package/esm/utils/padding.d.ts +1 -0
- package/esm/utils/padding.js +6 -2
- package/esm/version.d.ts +1 -1
- package/esm/version.js +1 -1
- package/lib/editor/commands/UpdateOptions.d.ts +4 -4
- package/lib/editor/commands/UpdateOptions.js +6 -3
- package/lib/editor/editor.d.ts +5 -1
- package/lib/editor/editor.js +16 -5
- package/lib/editor/index.d.ts +1 -0
- package/lib/editor/index.js +1 -0
- package/lib/editor/interactions/brush-select.d.ts +0 -1
- package/lib/editor/interactions/brush-select.js +1 -9
- package/lib/editor/interactions/drag-canvas.d.ts +35 -0
- package/lib/editor/interactions/drag-canvas.js +165 -0
- package/lib/editor/interactions/drag-element.js +4 -3
- package/lib/editor/interactions/index.d.ts +1 -0
- package/lib/editor/interactions/index.js +3 -1
- package/lib/editor/interactions/zoom-wheel.d.ts +9 -0
- package/lib/editor/interactions/zoom-wheel.js +32 -15
- package/lib/editor/managers/index.d.ts +1 -0
- package/lib/editor/managers/index.js +1 -0
- package/lib/editor/managers/state.d.ts +4 -2
- package/lib/editor/managers/state.js +12 -11
- package/lib/editor/managers/sync-registry.d.ts +15 -0
- package/lib/editor/managers/sync-registry.js +55 -0
- package/lib/editor/plugins/{edit-bar/components → components}/button.js +1 -1
- package/lib/editor/plugins/{edit-bar/components → components}/color-picker.js +1 -1
- package/lib/editor/plugins/{edit-bar/components → components}/icons.d.ts +1 -0
- package/lib/editor/plugins/{edit-bar/components → components}/icons.js +2 -1
- package/lib/editor/plugins/{edit-bar/components → components}/popover.js +2 -2
- package/lib/editor/plugins/{edit-bar/components → components}/select.js +1 -1
- package/lib/editor/plugins/core-sync.d.ts +8 -0
- package/lib/editor/plugins/core-sync.js +34 -0
- package/lib/editor/plugins/edit-bar/edit-items/align-elements.js +1 -1
- package/lib/editor/plugins/edit-bar/edit-items/font-align.js +1 -1
- package/lib/editor/plugins/edit-bar/edit-items/font-color.js +1 -1
- package/lib/editor/plugins/edit-bar/edit-items/font-family.js +1 -1
- package/lib/editor/plugins/edit-bar/edit-items/font-size.js +1 -1
- package/lib/editor/plugins/edit-bar/edit-items/icon-color.js +1 -1
- package/lib/editor/plugins/edit-bar/index.d.ts +2 -2
- package/lib/editor/plugins/edit-bar/index.js +1 -1
- package/lib/editor/plugins/index.d.ts +2 -0
- package/lib/editor/plugins/index.js +5 -1
- package/lib/editor/plugins/reset-viewbox.d.ts +33 -0
- package/lib/editor/plugins/reset-viewbox.js +190 -0
- package/lib/editor/types/editor.d.ts +13 -0
- package/lib/editor/types/index.d.ts +1 -0
- package/lib/editor/types/interaction.d.ts +9 -0
- package/lib/editor/types/state.d.ts +4 -2
- package/lib/editor/types/sync.d.ts +26 -0
- package/lib/editor/types/sync.js +2 -0
- package/lib/editor/utils/data.js +3 -1
- package/lib/editor/utils/event.d.ts +1 -0
- package/lib/editor/utils/event.js +9 -0
- package/lib/editor/utils/index.d.ts +1 -0
- package/lib/editor/utils/index.js +1 -0
- package/lib/editor/utils/object.d.ts +15 -0
- package/lib/editor/utils/object.js +73 -0
- package/lib/index.d.ts +4 -3
- package/lib/index.js +9 -2
- package/lib/options/types.d.ts +1 -0
- package/lib/runtime/options.js +6 -1
- package/lib/templates/built-in.js +24 -0
- package/lib/utils/measure-text.js +9 -6
- package/lib/utils/padding.d.ts +1 -0
- package/lib/utils/padding.js +7 -2
- package/lib/version.d.ts +1 -1
- package/lib/version.js +1 -1
- package/package.json +1 -1
- package/src/editor/commands/UpdateOptions.ts +11 -6
- package/src/editor/editor.ts +26 -5
- package/src/editor/index.ts +1 -0
- package/src/editor/interactions/brush-select.ts +2 -8
- package/src/editor/interactions/drag-canvas.ts +203 -0
- package/src/editor/interactions/drag-element.ts +5 -4
- package/src/editor/interactions/index.ts +1 -0
- package/src/editor/interactions/zoom-wheel.ts +49 -13
- package/src/editor/managers/index.ts +1 -0
- package/src/editor/managers/state.ts +21 -21
- package/src/editor/managers/sync-registry.ts +65 -0
- package/src/editor/plugins/{edit-bar/components → components}/button.ts +1 -1
- package/src/editor/plugins/{edit-bar/components → components}/color-picker.ts +1 -1
- package/src/editor/plugins/{edit-bar/components → components}/icons.ts +4 -0
- package/src/editor/plugins/{edit-bar/components → components}/popover.ts +2 -2
- package/src/editor/plugins/{edit-bar/components → components}/select.ts +1 -1
- package/src/editor/plugins/core-sync.ts +44 -0
- package/src/editor/plugins/edit-bar/edit-items/align-elements.ts +2 -2
- package/src/editor/plugins/edit-bar/edit-items/font-align.ts +1 -1
- package/src/editor/plugins/edit-bar/edit-items/font-color.ts +1 -1
- package/src/editor/plugins/edit-bar/edit-items/font-family.ts +1 -1
- package/src/editor/plugins/edit-bar/edit-items/font-size.ts +3 -3
- package/src/editor/plugins/edit-bar/edit-items/icon-color.ts +1 -1
- package/src/editor/plugins/edit-bar/index.ts +2 -2
- package/src/editor/plugins/index.ts +2 -0
- package/src/editor/plugins/reset-viewbox.ts +258 -0
- package/src/editor/types/editor.ts +17 -0
- package/src/editor/types/index.ts +1 -0
- package/src/editor/types/interaction.ts +31 -0
- package/src/editor/types/state.ts +14 -2
- package/src/editor/types/sync.ts +31 -0
- package/src/editor/utils/data.ts +2 -1
- package/src/editor/utils/event.ts +7 -0
- package/src/editor/utils/index.ts +1 -0
- package/src/editor/utils/object.ts +106 -0
- package/src/index.ts +26 -2
- package/src/options/types.ts +4 -0
- package/src/runtime/options.ts +8 -1
- package/src/templates/built-in.ts +28 -0
- package/src/utils/measure-text.ts +6 -6
- package/src/utils/padding.ts +10 -2
- package/src/version.ts +1 -1
- /package/esm/editor/plugins/{edit-bar/components → components}/button.d.ts +0 -0
- /package/esm/editor/plugins/{edit-bar/components → components}/color-picker.d.ts +0 -0
- /package/esm/editor/plugins/{edit-bar/components → components}/index.d.ts +0 -0
- /package/esm/editor/plugins/{edit-bar/components → components}/index.js +0 -0
- /package/esm/editor/plugins/{edit-bar/components → components}/popover.d.ts +0 -0
- /package/esm/editor/plugins/{edit-bar/components → components}/select.d.ts +0 -0
- /package/lib/editor/plugins/{edit-bar/components → components}/button.d.ts +0 -0
- /package/lib/editor/plugins/{edit-bar/components → components}/color-picker.d.ts +0 -0
- /package/lib/editor/plugins/{edit-bar/components → components}/index.d.ts +0 -0
- /package/lib/editor/plugins/{edit-bar/components → components}/index.js +0 -0
- /package/lib/editor/plugins/{edit-bar/components → components}/popover.d.ts +0 -0
- /package/lib/editor/plugins/{edit-bar/components → components}/select.d.ts +0 -0
- /package/src/editor/plugins/{edit-bar/components → components}/index.ts +0 -0
package/package.json
CHANGED
|
@@ -1,18 +1,23 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { UpdatableInfographicOptions } from '../../options';
|
|
2
2
|
import type { ICommand, IStateManager } from '../types';
|
|
3
3
|
|
|
4
4
|
export class UpdateOptionsCommand implements ICommand {
|
|
5
5
|
constructor(
|
|
6
|
-
private options:
|
|
7
|
-
private original?:
|
|
6
|
+
private options: UpdatableInfographicOptions,
|
|
7
|
+
private original?: UpdatableInfographicOptions,
|
|
8
8
|
) {}
|
|
9
9
|
|
|
10
10
|
async apply(state: IStateManager) {
|
|
11
|
-
const prev = state.getOptions();
|
|
12
11
|
if (!this.original) {
|
|
13
|
-
|
|
12
|
+
const prev = state.getOptions();
|
|
13
|
+
this.original = {};
|
|
14
|
+
(
|
|
15
|
+
Object.keys(this.options) as Array<keyof UpdatableInfographicOptions>
|
|
16
|
+
).forEach((key) => {
|
|
17
|
+
(this.original as any)[key] = prev[key];
|
|
18
|
+
});
|
|
14
19
|
}
|
|
15
|
-
state.updateOptions(
|
|
20
|
+
state.updateOptions(this.options);
|
|
16
21
|
}
|
|
17
22
|
|
|
18
23
|
async undo(state: IStateManager) {
|
package/src/editor/editor.ts
CHANGED
|
@@ -6,11 +6,15 @@ import {
|
|
|
6
6
|
PluginManager,
|
|
7
7
|
StateManager,
|
|
8
8
|
} from './managers';
|
|
9
|
+
import { SyncRegistry } from './managers/sync-registry';
|
|
10
|
+
import { CoreSyncPlugin } from './plugins';
|
|
9
11
|
import type {
|
|
10
12
|
ICommandManager,
|
|
11
13
|
IEditor,
|
|
12
14
|
IPluginManager,
|
|
13
15
|
IStateManager,
|
|
16
|
+
ISyncRegistry,
|
|
17
|
+
SyncHandler,
|
|
14
18
|
} from './types';
|
|
15
19
|
|
|
16
20
|
export class Editor implements IEditor {
|
|
@@ -18,6 +22,7 @@ export class Editor implements IEditor {
|
|
|
18
22
|
commander: ICommandManager;
|
|
19
23
|
plugin: IPluginManager;
|
|
20
24
|
interaction: InteractionManager;
|
|
25
|
+
syncRegistry: ISyncRegistry;
|
|
21
26
|
|
|
22
27
|
constructor(
|
|
23
28
|
private emitter: IEventEmitter,
|
|
@@ -34,6 +39,14 @@ export class Editor implements IEditor {
|
|
|
34
39
|
const plugin = new PluginManager();
|
|
35
40
|
const interaction = new InteractionManager();
|
|
36
41
|
|
|
42
|
+
const syncRegistry = new SyncRegistry(() => state.getOptions());
|
|
43
|
+
|
|
44
|
+
this.commander = commander;
|
|
45
|
+
this.state = state;
|
|
46
|
+
this.plugin = plugin;
|
|
47
|
+
this.interaction = interaction;
|
|
48
|
+
this.syncRegistry = syncRegistry;
|
|
49
|
+
|
|
37
50
|
commander.init({ state, emitter });
|
|
38
51
|
state.init({
|
|
39
52
|
emitter,
|
|
@@ -41,6 +54,10 @@ export class Editor implements IEditor {
|
|
|
41
54
|
commander,
|
|
42
55
|
options,
|
|
43
56
|
});
|
|
57
|
+
// Load core plugin: CoreSyncPlugin (handles viewBox/padding sync)
|
|
58
|
+
const corePlugin = new CoreSyncPlugin();
|
|
59
|
+
const userPlugins = options.plugins || [];
|
|
60
|
+
|
|
44
61
|
plugin.init(
|
|
45
62
|
{
|
|
46
63
|
emitter,
|
|
@@ -48,7 +65,7 @@ export class Editor implements IEditor {
|
|
|
48
65
|
commander,
|
|
49
66
|
state,
|
|
50
67
|
},
|
|
51
|
-
|
|
68
|
+
[corePlugin, ...userPlugins],
|
|
52
69
|
);
|
|
53
70
|
interaction.init({
|
|
54
71
|
emitter,
|
|
@@ -57,11 +74,14 @@ export class Editor implements IEditor {
|
|
|
57
74
|
state,
|
|
58
75
|
interactions: options.interactions,
|
|
59
76
|
});
|
|
77
|
+
}
|
|
60
78
|
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
79
|
+
registerSync(
|
|
80
|
+
path: string,
|
|
81
|
+
handler: SyncHandler,
|
|
82
|
+
options?: { immediate?: boolean },
|
|
83
|
+
) {
|
|
84
|
+
return this.syncRegistry.register(path, handler, options);
|
|
65
85
|
}
|
|
66
86
|
|
|
67
87
|
getDocument() {
|
|
@@ -74,5 +94,6 @@ export class Editor implements IEditor {
|
|
|
74
94
|
this.plugin.destroy();
|
|
75
95
|
this.commander.destroy();
|
|
76
96
|
this.state.destroy();
|
|
97
|
+
this.syncRegistry.destroy();
|
|
77
98
|
}
|
|
78
99
|
}
|
package/src/editor/index.ts
CHANGED
|
@@ -5,6 +5,7 @@ import {
|
|
|
5
5
|
getElementViewportBounds,
|
|
6
6
|
getEventTarget,
|
|
7
7
|
getSelectableTarget,
|
|
8
|
+
isTextSelectionTarget,
|
|
8
9
|
} from '../utils';
|
|
9
10
|
import { Interaction } from './base';
|
|
10
11
|
|
|
@@ -38,7 +39,7 @@ export class BrushSelect extends Interaction implements IInteraction {
|
|
|
38
39
|
private handleStart = (event: PointerEvent) => {
|
|
39
40
|
if (!this.interaction.isActive()) return;
|
|
40
41
|
if (event.button !== 0) return;
|
|
41
|
-
if (
|
|
42
|
+
if (isTextSelectionTarget(event.target)) return;
|
|
42
43
|
if (this.hasElementAtStart(event.target)) return;
|
|
43
44
|
|
|
44
45
|
this.interaction.executeExclusiveInteraction(
|
|
@@ -194,11 +195,4 @@ export class BrushSelect extends Interaction implements IInteraction {
|
|
|
194
195
|
if (getEventTarget(target as unknown as SVGElement)) return true;
|
|
195
196
|
return Boolean(target.closest?.('[data-element-type]'));
|
|
196
197
|
}
|
|
197
|
-
|
|
198
|
-
private isTextSelectionTarget(target: EventTarget | null) {
|
|
199
|
-
if (!(target instanceof HTMLElement)) return false;
|
|
200
|
-
if (target.isContentEditable) return true;
|
|
201
|
-
const tag = target.tagName.toLowerCase();
|
|
202
|
-
return tag === 'input' || tag === 'textarea';
|
|
203
|
-
}
|
|
204
198
|
}
|
|
@@ -0,0 +1,203 @@
|
|
|
1
|
+
import { getViewBox, viewBoxToString } from '../../utils';
|
|
2
|
+
import { UpdateOptionsCommand } from '../commands';
|
|
3
|
+
import { IInteraction, InteractionInitOptions, KeyCode } from '../types';
|
|
4
|
+
import { clientToViewport, isTextSelectionTarget } from '../utils';
|
|
5
|
+
import { Interaction } from './base';
|
|
6
|
+
|
|
7
|
+
type CursorType = 'grab' | 'grabbing' | 'default';
|
|
8
|
+
export interface DragCanvasOptions {
|
|
9
|
+
trigger?: KeyCode[];
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export class DragCanvas extends Interaction implements IInteraction {
|
|
13
|
+
name = 'drag-canvas';
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* 触发交互的按键代码。
|
|
17
|
+
* 参考标准的 KeyboardEvent.code 值:
|
|
18
|
+
* https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/code/code_values
|
|
19
|
+
* @default ['Space']
|
|
20
|
+
*/
|
|
21
|
+
public trigger: KeyCode[] = ['Space'];
|
|
22
|
+
|
|
23
|
+
constructor(options?: DragCanvasOptions) {
|
|
24
|
+
super();
|
|
25
|
+
if (options?.trigger) {
|
|
26
|
+
this.trigger = options.trigger;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
private isTriggerPressed = false;
|
|
31
|
+
|
|
32
|
+
private pointerId?: number;
|
|
33
|
+
private startPoint?: DOMPoint;
|
|
34
|
+
|
|
35
|
+
private document!: SVGSVGElement;
|
|
36
|
+
|
|
37
|
+
private startViewBoxString?: string;
|
|
38
|
+
|
|
39
|
+
private completeInteraction?: () => void;
|
|
40
|
+
|
|
41
|
+
// 防止组件快捷键侵入性过强
|
|
42
|
+
private isHovering = false;
|
|
43
|
+
|
|
44
|
+
init(options: InteractionInitOptions): void {
|
|
45
|
+
super.init(options);
|
|
46
|
+
this.document = this.editor.getDocument();
|
|
47
|
+
|
|
48
|
+
this.document.addEventListener('mouseenter', this.onMouseEnter);
|
|
49
|
+
this.document.addEventListener('mouseleave', this.onMouseLeave);
|
|
50
|
+
window.addEventListener('keydown', this.handleKeyDown);
|
|
51
|
+
window.addEventListener('blur', this.handleBlur);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
destroy(): void {
|
|
55
|
+
window.removeEventListener('keydown', this.handleKeyDown);
|
|
56
|
+
window.removeEventListener('keyup', this.handleKeyUp);
|
|
57
|
+
|
|
58
|
+
this.document.removeEventListener('pointerdown', this.handlePointerDown);
|
|
59
|
+
window.removeEventListener('pointermove', this.handlePointerMove);
|
|
60
|
+
window.removeEventListener('pointerup', this.handlePointerUp);
|
|
61
|
+
window.removeEventListener('pointercancel', this.handlePointerUp);
|
|
62
|
+
|
|
63
|
+
window.removeEventListener('blur', this.handleBlur);
|
|
64
|
+
this.document.removeEventListener('mouseenter', this.onMouseEnter);
|
|
65
|
+
this.document.removeEventListener('mouseleave', this.onMouseLeave);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
private handleKeyDown = (event: KeyboardEvent) => {
|
|
69
|
+
if (!this.interaction.isActive()) return;
|
|
70
|
+
if (isTextSelectionTarget(event.target)) return;
|
|
71
|
+
|
|
72
|
+
// 增加焦点的判断,防止对空格的preventDefault侵入性过强
|
|
73
|
+
const target = event.target as Element;
|
|
74
|
+
const isBody =
|
|
75
|
+
target === document.body || target === document.documentElement;
|
|
76
|
+
const isEditor = target === this.document || this.document.contains(target);
|
|
77
|
+
if (!isBody && !isEditor) return;
|
|
78
|
+
|
|
79
|
+
if (!this.trigger.includes(event.code)) return;
|
|
80
|
+
if (!this.isHovering && !this.isTriggerPressed) return;
|
|
81
|
+
event.preventDefault();
|
|
82
|
+
event.stopPropagation();
|
|
83
|
+
this.interaction.executeExclusiveInteraction(
|
|
84
|
+
this,
|
|
85
|
+
async () =>
|
|
86
|
+
new Promise<void>((resolve) => {
|
|
87
|
+
this.completeInteraction = resolve;
|
|
88
|
+
|
|
89
|
+
this.isTriggerPressed = true;
|
|
90
|
+
const viewBox = getViewBox(this.document);
|
|
91
|
+
|
|
92
|
+
this.startViewBoxString = viewBoxToString(viewBox);
|
|
93
|
+
this.setCursor('grab');
|
|
94
|
+
|
|
95
|
+
this.document.addEventListener('pointerdown', this.handlePointerDown);
|
|
96
|
+
window.addEventListener('keyup', this.handleKeyUp);
|
|
97
|
+
}),
|
|
98
|
+
);
|
|
99
|
+
};
|
|
100
|
+
|
|
101
|
+
private handlePointerDown = (event: PointerEvent) => {
|
|
102
|
+
if (event.button !== 0) return;
|
|
103
|
+
event.preventDefault();
|
|
104
|
+
event.stopPropagation();
|
|
105
|
+
|
|
106
|
+
const svg = this.document;
|
|
107
|
+
this.startPoint = clientToViewport(svg, event.clientX, event.clientY);
|
|
108
|
+
this.pointerId = event.pointerId;
|
|
109
|
+
|
|
110
|
+
this.setCursor('grabbing');
|
|
111
|
+
|
|
112
|
+
window.addEventListener('pointermove', this.handlePointerMove);
|
|
113
|
+
window.addEventListener('pointerup', this.handlePointerUp);
|
|
114
|
+
window.addEventListener('pointercancel', this.handlePointerUp);
|
|
115
|
+
};
|
|
116
|
+
|
|
117
|
+
private handlePointerMove = (event: PointerEvent) => {
|
|
118
|
+
if (event.pointerId !== this.pointerId || !this.startPoint) return;
|
|
119
|
+
event.preventDefault();
|
|
120
|
+
event.stopPropagation();
|
|
121
|
+
|
|
122
|
+
const svg = this.document;
|
|
123
|
+
const current = clientToViewport(svg, event.clientX, event.clientY);
|
|
124
|
+
const dx = current.x - this.startPoint.x;
|
|
125
|
+
const dy = current.y - this.startPoint.y;
|
|
126
|
+
|
|
127
|
+
const viewBox = getViewBox(svg);
|
|
128
|
+
|
|
129
|
+
const { x, y, width, height } = viewBox;
|
|
130
|
+
|
|
131
|
+
const newX = x - dx;
|
|
132
|
+
const newY = y - dy;
|
|
133
|
+
|
|
134
|
+
this.state.updateOptions({
|
|
135
|
+
viewBox: viewBoxToString({ x: newX, y: newY, width, height }),
|
|
136
|
+
});
|
|
137
|
+
};
|
|
138
|
+
|
|
139
|
+
private handlePointerUp = (event: PointerEvent) => {
|
|
140
|
+
if (event.pointerId !== this.pointerId) return;
|
|
141
|
+
|
|
142
|
+
this.startPoint = undefined;
|
|
143
|
+
this.pointerId = undefined;
|
|
144
|
+
this.setCursor('grab');
|
|
145
|
+
window.removeEventListener('pointermove', this.handlePointerMove);
|
|
146
|
+
window.removeEventListener('pointerup', this.handlePointerUp);
|
|
147
|
+
window.removeEventListener('pointercancel', this.handlePointerUp);
|
|
148
|
+
};
|
|
149
|
+
|
|
150
|
+
private handleKeyUp = (event: KeyboardEvent) => {
|
|
151
|
+
if (!this.trigger.includes(event.code)) return;
|
|
152
|
+
this.stopDrag();
|
|
153
|
+
};
|
|
154
|
+
|
|
155
|
+
private stopDrag = () => {
|
|
156
|
+
if (this.startViewBoxString) {
|
|
157
|
+
const svg = this.document;
|
|
158
|
+
const viewBox = getViewBox(svg);
|
|
159
|
+
const currentViewBoxString = viewBoxToString(viewBox);
|
|
160
|
+
|
|
161
|
+
if (this.startViewBoxString !== currentViewBoxString) {
|
|
162
|
+
const command = new UpdateOptionsCommand(
|
|
163
|
+
{ viewBox: currentViewBoxString },
|
|
164
|
+
{ viewBox: this.startViewBoxString },
|
|
165
|
+
);
|
|
166
|
+
void this.commander.execute(command);
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
this.startViewBoxString = undefined;
|
|
170
|
+
|
|
171
|
+
this.isTriggerPressed = false;
|
|
172
|
+
|
|
173
|
+
this.setCursor('default');
|
|
174
|
+
|
|
175
|
+
this.startPoint = undefined;
|
|
176
|
+
this.pointerId = undefined;
|
|
177
|
+
|
|
178
|
+
window.removeEventListener('keyup', this.handleKeyUp);
|
|
179
|
+
|
|
180
|
+
this.document.removeEventListener('pointerdown', this.handlePointerDown);
|
|
181
|
+
window.removeEventListener('pointermove', this.handlePointerMove);
|
|
182
|
+
window.removeEventListener('pointerup', this.handlePointerUp);
|
|
183
|
+
window.removeEventListener('pointercancel', this.handlePointerUp);
|
|
184
|
+
|
|
185
|
+
this.completeInteraction?.();
|
|
186
|
+
this.completeInteraction = undefined;
|
|
187
|
+
};
|
|
188
|
+
|
|
189
|
+
private setCursor = (behavior: CursorType) => {
|
|
190
|
+
document.body.style.cursor = behavior;
|
|
191
|
+
};
|
|
192
|
+
|
|
193
|
+
private handleBlur = () => {
|
|
194
|
+
this.stopDrag();
|
|
195
|
+
};
|
|
196
|
+
|
|
197
|
+
private onMouseEnter = () => {
|
|
198
|
+
this.isHovering = true;
|
|
199
|
+
};
|
|
200
|
+
private onMouseLeave = () => {
|
|
201
|
+
this.isHovering = false;
|
|
202
|
+
};
|
|
203
|
+
}
|
|
@@ -157,10 +157,6 @@ export class DragElement extends Interaction implements IInteraction {
|
|
|
157
157
|
if (this.exclusiveStarted) return true;
|
|
158
158
|
if (!this.startTarget) return false;
|
|
159
159
|
|
|
160
|
-
if (this.willReplaceSelection) {
|
|
161
|
-
this.interaction.select([this.startTarget], 'replace');
|
|
162
|
-
}
|
|
163
|
-
|
|
164
160
|
this.dragItems = this.selectionForDrag
|
|
165
161
|
.filter((element) => isEditableText(element))
|
|
166
162
|
.map((element) => this.createDragItem(element))
|
|
@@ -173,6 +169,11 @@ export class DragElement extends Interaction implements IInteraction {
|
|
|
173
169
|
this,
|
|
174
170
|
async () =>
|
|
175
171
|
new Promise<void>((resolve) => {
|
|
172
|
+
// 只有拿到锁之后,才真正执行选中逻辑
|
|
173
|
+
if (this.willReplaceSelection && this.startTarget) {
|
|
174
|
+
this.interaction.select([this.startTarget], 'replace');
|
|
175
|
+
}
|
|
176
|
+
|
|
176
177
|
this.completeInteraction = resolve;
|
|
177
178
|
started = true;
|
|
178
179
|
}),
|
|
@@ -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';
|
|
@@ -9,12 +9,50 @@ import type { IInteraction, InteractionInitOptions } from '../types';
|
|
|
9
9
|
import { clientToViewport } from '../utils';
|
|
10
10
|
import { Interaction } from './base';
|
|
11
11
|
|
|
12
|
-
|
|
13
|
-
|
|
12
|
+
export interface ZoomWheelOptions {
|
|
13
|
+
minViewBoxSize?: number;
|
|
14
|
+
maxViewBoxSize?: number;
|
|
15
|
+
}
|
|
16
|
+
|
|
14
17
|
const ZOOM_FACTOR = 1.1;
|
|
15
18
|
|
|
16
19
|
export class ZoomWheel extends Interaction implements IInteraction {
|
|
17
20
|
name = 'zoom-wheel';
|
|
21
|
+
private minViewBoxSize = 20;
|
|
22
|
+
private maxViewBoxSize = 20000;
|
|
23
|
+
|
|
24
|
+
constructor(options?: ZoomWheelOptions) {
|
|
25
|
+
super();
|
|
26
|
+
if (options?.minViewBoxSize !== undefined) {
|
|
27
|
+
this.minViewBoxSize = options.minViewBoxSize;
|
|
28
|
+
}
|
|
29
|
+
if (options?.maxViewBoxSize !== undefined) {
|
|
30
|
+
this.maxViewBoxSize = options.maxViewBoxSize;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
private initialViewBox: string | null = null;
|
|
35
|
+
|
|
36
|
+
private handleKeyUp = (event: KeyboardEvent) => {
|
|
37
|
+
const isZoomModifierHeld = event.ctrlKey || event.metaKey || event.shiftKey;
|
|
38
|
+
|
|
39
|
+
if (!isZoomModifierHeld && this.initialViewBox) {
|
|
40
|
+
const currentViewBox = viewBoxToString(
|
|
41
|
+
getViewBox(this.editor.getDocument()),
|
|
42
|
+
);
|
|
43
|
+
|
|
44
|
+
if (currentViewBox !== this.initialViewBox) {
|
|
45
|
+
const command = new UpdateOptionsCommand(
|
|
46
|
+
{ viewBox: currentViewBox },
|
|
47
|
+
{ viewBox: this.initialViewBox },
|
|
48
|
+
);
|
|
49
|
+
void this.commander.execute(command);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
this.initialViewBox = null;
|
|
53
|
+
document.removeEventListener('keyup', this.handleKeyUp);
|
|
54
|
+
}
|
|
55
|
+
};
|
|
18
56
|
|
|
19
57
|
private wheelListener = (event: WheelEvent) => {
|
|
20
58
|
if (!this.shouldZoom(event)) return;
|
|
@@ -32,19 +70,16 @@ export class ZoomWheel extends Interaction implements IInteraction {
|
|
|
32
70
|
const newHeight = height * factor;
|
|
33
71
|
|
|
34
72
|
if (
|
|
35
|
-
!inRange(newWidth,
|
|
36
|
-
!inRange(newHeight,
|
|
73
|
+
!inRange(newWidth, this.minViewBoxSize, this.maxViewBoxSize) ||
|
|
74
|
+
!inRange(newHeight, this.minViewBoxSize, this.maxViewBoxSize)
|
|
37
75
|
)
|
|
38
76
|
return;
|
|
39
77
|
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
viewBox: undefined,
|
|
44
|
-
});
|
|
45
|
-
void this.commander.execute(command);
|
|
46
|
-
return;
|
|
78
|
+
if (this.initialViewBox === null) {
|
|
79
|
+
this.initialViewBox = viewBoxToString(viewBox);
|
|
80
|
+
document.addEventListener('keyup', this.handleKeyUp);
|
|
47
81
|
}
|
|
82
|
+
|
|
48
83
|
const pivot =
|
|
49
84
|
(event.ctrlKey || event.metaKey) && !event.shiftKey
|
|
50
85
|
? this.getMousePoint(svg, event)
|
|
@@ -52,10 +87,9 @@ export class ZoomWheel extends Interaction implements IInteraction {
|
|
|
52
87
|
|
|
53
88
|
const newViewBox = calculateZoomedViewBox(viewBox, factor, pivot);
|
|
54
89
|
|
|
55
|
-
|
|
90
|
+
this.state.updateOptions({
|
|
56
91
|
viewBox: viewBoxToString(newViewBox),
|
|
57
92
|
});
|
|
58
|
-
void this.commander.execute(command);
|
|
59
93
|
};
|
|
60
94
|
|
|
61
95
|
private getMousePoint = (svg: SVGSVGElement, event: WheelEvent) => {
|
|
@@ -79,6 +113,7 @@ export class ZoomWheel extends Interaction implements IInteraction {
|
|
|
79
113
|
|
|
80
114
|
const isMouseZoom = event.ctrlKey || event.metaKey;
|
|
81
115
|
const isCenterZoom = event.shiftKey;
|
|
116
|
+
if (isMouseZoom && isCenterZoom) return false;
|
|
82
117
|
|
|
83
118
|
return isMouseZoom || isCenterZoom;
|
|
84
119
|
};
|
|
@@ -90,5 +125,6 @@ export class ZoomWheel extends Interaction implements IInteraction {
|
|
|
90
125
|
|
|
91
126
|
destroy() {
|
|
92
127
|
document.removeEventListener('wheel', this.wheelListener);
|
|
128
|
+
document.removeEventListener('keyup', this.handleKeyUp);
|
|
93
129
|
}
|
|
94
130
|
}
|
|
@@ -1,13 +1,10 @@
|
|
|
1
1
|
import { ElementTypeEnum } from '../../constants';
|
|
2
|
-
import type {
|
|
2
|
+
import type {
|
|
3
|
+
ParsedInfographicOptions,
|
|
4
|
+
UpdatableInfographicOptions,
|
|
5
|
+
} from '../../options';
|
|
3
6
|
import type { Element, IEventEmitter, ItemDatum } from '../../types';
|
|
4
|
-
import {
|
|
5
|
-
getDatumByIndexes,
|
|
6
|
-
getElementRole,
|
|
7
|
-
isIconElement,
|
|
8
|
-
parsePadding,
|
|
9
|
-
setSVGPadding,
|
|
10
|
-
} from '../../utils';
|
|
7
|
+
import { getDatumByIndexes, getElementRole, isIconElement } from '../../utils';
|
|
11
8
|
import type {
|
|
12
9
|
ElementProps,
|
|
13
10
|
ICommandManager,
|
|
@@ -17,6 +14,7 @@ import type {
|
|
|
17
14
|
StateManagerInitOptions,
|
|
18
15
|
} from '../types';
|
|
19
16
|
import {
|
|
17
|
+
applyOptionUpdates,
|
|
20
18
|
buildItemPath,
|
|
21
19
|
getChildrenDataByIndexes,
|
|
22
20
|
getIndexesFromElement,
|
|
@@ -56,6 +54,7 @@ export class StateManager implements IStateManager {
|
|
|
56
54
|
|
|
57
55
|
updateItemDatum(indexes: number[], datum: Partial<ItemDatum>): void {
|
|
58
56
|
const item = getDatumByIndexes(this.options.data, indexes);
|
|
57
|
+
if (item == null || indexes.length === 0) return;
|
|
59
58
|
Object.assign(item, datum);
|
|
60
59
|
this.emitter.emit('options:data:item:update', { indexes, datum });
|
|
61
60
|
this.emitter.emit('options:change', {
|
|
@@ -111,19 +110,19 @@ export class StateManager implements IStateManager {
|
|
|
111
110
|
this.updateBuiltInElement(element, props);
|
|
112
111
|
}
|
|
113
112
|
|
|
114
|
-
updateOptions(
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
113
|
+
updateOptions(
|
|
114
|
+
options: UpdatableInfographicOptions,
|
|
115
|
+
execOptions?: { bubbleUp?: boolean },
|
|
116
|
+
) {
|
|
117
|
+
const { bubbleUp = false } = execOptions || {};
|
|
118
|
+
|
|
119
|
+
applyOptionUpdates(this.options, options, '', {
|
|
120
|
+
bubbleUp,
|
|
121
|
+
collector: (path, newVal, oldVal) => {
|
|
122
|
+
this.editor.syncRegistry.trigger(path, newVal, oldVal);
|
|
123
|
+
},
|
|
124
|
+
});
|
|
125
|
+
|
|
127
126
|
this.emitter.emit('options:change', {
|
|
128
127
|
type: 'options:change',
|
|
129
128
|
changes: [
|
|
@@ -156,6 +155,7 @@ export class StateManager implements IStateManager {
|
|
|
156
155
|
const indexes = isItemElement ? getIndexesFromElement(element) : undefined;
|
|
157
156
|
if (isItemElement) {
|
|
158
157
|
const datum = getDatumByIndexes(data, indexes!);
|
|
158
|
+
if (datum == null) return;
|
|
159
159
|
const key = role.replace('item-', '');
|
|
160
160
|
datum.attributes ||= {};
|
|
161
161
|
datum.attributes[key] ||= {};
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { get } from 'lodash-es';
|
|
2
|
+
import { ISyncRegistry, SyncHandler } from '../types';
|
|
3
|
+
|
|
4
|
+
type OptionsGetter = () => any;
|
|
5
|
+
|
|
6
|
+
export class SyncRegistry implements ISyncRegistry {
|
|
7
|
+
private handlers = new Map<string, Set<SyncHandler>>();
|
|
8
|
+
// lock to prevent recursive updates
|
|
9
|
+
private isDispatching = false;
|
|
10
|
+
private isDestroyed = false;
|
|
11
|
+
|
|
12
|
+
constructor(private getOptions: OptionsGetter) {}
|
|
13
|
+
|
|
14
|
+
register(
|
|
15
|
+
path: string,
|
|
16
|
+
handler: SyncHandler,
|
|
17
|
+
options?: { immediate?: boolean },
|
|
18
|
+
): () => void {
|
|
19
|
+
if (!this.handlers.has(path)) {
|
|
20
|
+
this.handlers.set(path, new Set());
|
|
21
|
+
}
|
|
22
|
+
this.handlers.get(path)!.add(handler);
|
|
23
|
+
|
|
24
|
+
if (options?.immediate) {
|
|
25
|
+
const currentVal = get(this.getOptions(), path);
|
|
26
|
+
handler(currentVal, undefined);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
return () => {
|
|
30
|
+
const set = this.handlers.get(path);
|
|
31
|
+
if (set) {
|
|
32
|
+
set.delete(handler);
|
|
33
|
+
if (set.size === 0) {
|
|
34
|
+
this.handlers.delete(path);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
trigger(path: string, newVal: any, oldVal: any): void {
|
|
40
|
+
if (this.isDestroyed || this.isDispatching) {
|
|
41
|
+
if (this.isDispatching) {
|
|
42
|
+
console.warn(
|
|
43
|
+
`[SyncRegistry] Recursive update detected on ${path}. Skipped to prevent loop.`,
|
|
44
|
+
);
|
|
45
|
+
}
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
const handlers = this.handlers.get(path);
|
|
50
|
+
|
|
51
|
+
if (handlers) {
|
|
52
|
+
this.isDispatching = true;
|
|
53
|
+
try {
|
|
54
|
+
handlers.forEach((fn) => fn(newVal, oldVal));
|
|
55
|
+
} finally {
|
|
56
|
+
this.isDispatching = false;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
destroy() {
|
|
62
|
+
this.isDestroyed = true;
|
|
63
|
+
this.handlers.clear();
|
|
64
|
+
}
|
|
65
|
+
}
|
|
@@ -54,6 +54,10 @@ export const TEXT_ICONS = {
|
|
|
54
54
|
),
|
|
55
55
|
};
|
|
56
56
|
|
|
57
|
+
export const RESET_ICON = createIcon(
|
|
58
|
+
`<path d="M502.714987 58.258904l-126.531056-54.617723a52.797131 52.797131 0 0 0-41.873587 96.855428A447.865322 447.865322 0 0 0 392.02307 946.707184a61.535967 61.535967 0 0 0 13.83649 1.820591 52.797131 52.797131 0 0 0 13.65443-103.773672 342.453118 342.453118 0 0 1-31.678278-651.771485l-8.374718 19.480321a52.615072 52.615072 0 0 0 27.855039 69.182448 51.522718 51.522718 0 0 0 20.572675 4.369418A52.797131 52.797131 0 0 0 476.498481 254.882703L530.205907 127.441352a52.979191 52.979191 0 0 0-27.49092-69.182448zM962.960326 509.765407A448.775617 448.775617 0 0 0 643.992829 68.090094a52.797131 52.797131 0 1 0-30.403866 101.042786A342.635177 342.635177 0 0 1 674.578753 801.059925a52.615072 52.615072 0 0 0-92.30395-50.612422l-71.913335 117.246043a52.433013 52.433013 0 0 0 17.295612 72.82363l117.063985 72.823629a52.797131 52.797131 0 1 0 54.617722-89.755123l-16.021198-10.013249A448.593558 448.593558 0 0 0 962.960326 509.765407z" p-id="1630"/>`,
|
|
59
|
+
);
|
|
60
|
+
|
|
57
61
|
export const ELEMENT_ICONS = {
|
|
58
62
|
align: createIcon(
|
|
59
63
|
`<path d="M555.188 715.059c17.673 0 32 14.327 32 32V875c0 17.673-14.327 32-32 32H171c-17.673 0-32-14.327-32-32V747.059c0-17.673 14.327-32 32-32z m-32.001 63.999H203V843h320.187v-63.942zM854 416.529c17.673 0 32 14.327 32 32v127.942c0 17.673-14.327 32-32 32H171c-17.673 0-32-14.327-32-32V448.529c0-17.673 14.327-32 32-32z m-32 64H203v63.941h619v-63.941zM683.25 118c17.673 0 32 14.327 32 32v127.941c0 17.673-14.327 32-32 32H171c-17.673 0-32-14.327-32-32V150c0-17.673 14.327-32 32-32z m-32 64H203v63.941h448.25V182z"></path>`,
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { COMPONENT_ROLE } from '
|
|
2
|
-
import { injectStyleOnce, setElementRole } from '
|
|
1
|
+
import { COMPONENT_ROLE } from '../../../constants';
|
|
2
|
+
import { injectStyleOnce, setElementRole } from '../../../utils';
|
|
3
3
|
|
|
4
4
|
export type PopoverPlacement = 'top' | 'bottom' | 'left' | 'right';
|
|
5
5
|
export type PopoverPlacementPreference = PopoverPlacement | PopoverPlacement[];
|