vue-echarts 8.2.0 → 8.3.0
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/README.md +12 -3
- package/README.zh-Hans.md +13 -3
- package/dist/graphic.d.ts +2 -3
- package/dist/graphic.js +147 -115
- package/dist/graphic.js.map +1 -1
- package/dist/index.js +158 -300
- package/dist/index.js.map +1 -1
- package/dist/index.min.js +2 -2
- package/dist/index.min.js.map +1 -1
- package/dist/update-CWPvYl2M.js +239 -0
- package/dist/update-CWPvYl2M.js.map +1 -0
- package/package.json +10 -14
- package/dist/runtime-BSiQKM1W.js +0 -64
- package/dist/runtime-BSiQKM1W.js.map +0 -1
package/README.md
CHANGED
|
@@ -122,7 +122,7 @@ Drop `<script>` inside your HTML file and access the component via `window.VueEC
|
|
|
122
122
|
```html
|
|
123
123
|
<script src="https://cdn.jsdelivr.net/npm/echarts@6.1.0"></script>
|
|
124
124
|
<script src="https://cdn.jsdelivr.net/npm/vue@3.5.41"></script>
|
|
125
|
-
<script src="https://cdn.jsdelivr.net/npm/vue-echarts@8.
|
|
125
|
+
<script src="https://cdn.jsdelivr.net/npm/vue-echarts@8.3.0"></script>
|
|
126
126
|
```
|
|
127
127
|
|
|
128
128
|
<!-- scripts:end -->
|
|
@@ -152,6 +152,8 @@ See more examples [here](https://github.com/ecomfe/vue-echarts/tree/main/demo).
|
|
|
152
152
|
|
|
153
153
|
Pass an empty string to use ECharts' default theme while overriding an injected theme.
|
|
154
154
|
|
|
155
|
+
ECharts recreates its model when changing themes. Vue ECharts reapplies the latest automatic option, but uncontrolled interaction state (such as legend selection or data zoom) may reset. Keep state that must survive a rebuild in `option`.
|
|
156
|
+
|
|
155
157
|
Injection key: `THEME_KEY`.
|
|
156
158
|
|
|
157
159
|
- `option: object`
|
|
@@ -160,9 +162,14 @@ See more examples [here](https://github.com/ecomfe/vue-echarts/tree/main/demo).
|
|
|
160
162
|
Temporarily removing the prop pauses automatic updates without letting a later theme change roll the chart back to its initial option.
|
|
161
163
|
|
|
162
164
|
#### Smart update
|
|
163
|
-
|
|
165
|
+
|
|
166
|
+
Reactive updates describe the complete configuration. Vue ECharts preserves existing models where merging can apply that configuration, and rebuilds when necessary to remove stale settings. A rebuild can reset interaction state such as legend selections and data zoom.
|
|
167
|
+
|
|
168
|
+
- If you supply `update-options` (via prop or injection), Vue ECharts forwards it directly to `setOption` and skips the planner. After you remove it, the first smart source-option update rebuilds once to establish a safe structural baseline.
|
|
169
|
+
- A failed option or theme submission invalidates that baseline. The next smart update rebuilds instead of trusting a potentially partial update.
|
|
170
|
+
- Automatic option, theme, and slot changes are batched after Vue updates. `clear()` takes effect immediately and cancels already queued automatic work; later changes can populate the chart again.
|
|
164
171
|
- Manual `setOption` calls (only available when `manual-update` is `true`) behave like native ECharts, honouring only the per-call override you pass in and are not carried across re-initializations.
|
|
165
|
-
- Updates containing a graphic element `$action` keep normal merge for `graphic` so the command can target the existing element tree; safe removals of unrelated components still use `replaceMerge`.
|
|
172
|
+
- Updates containing a graphic element `$action` keep normal merge for `graphic` so the command can target the existing element tree; safe removals of unrelated components still use `replaceMerge`. Changes requiring a full rebuild cannot be applied together with these commands. For complete snapshot semantics, describe the resulting graphic tree without `$action` commands.
|
|
166
173
|
- Otherwise, Vue ECharts analyses the change: component removals, reordering, and deletions inside anonymous components use `replaceMerge` when it can reproduce the requested order; deletions inside ID-matched components, identity ordering that `replaceMerge` cannot reproduce, newly introduced or shrinking non-component arrays, first-time ARIA configuration, and other risky changes fall back to `notMerge: true`.
|
|
167
174
|
|
|
168
175
|
- `update-options: object`
|
|
@@ -542,6 +549,8 @@ Read more at [ECharts `option.graphic` →](https://echarts.apache.org/en/option
|
|
|
542
549
|
> - Path components accept `auto-batch` to opt into ZRender's Canvas path batching.
|
|
543
550
|
> - The `option` prop may be omitted for graphic-only charts.
|
|
544
551
|
> - `#graphic` overrides `option.graphic`. In `manual-update` mode, call `chartRef.setOption(...)` to apply changes.
|
|
552
|
+
> - Wrapper components and Fragments preserve their rendered graphic order. Compatible property changes update only changed elements, preserving unchanged elements and their running animations. Removing fields, changing types, or changing tree structure rebuilds the graphic component.
|
|
553
|
+
> - Graphic-only changes omit unrelated source options when safe. Explicit `notMerge` or `replaceMerge` targeting other components still submits the full source option.
|
|
545
554
|
|
|
546
555
|
<details>
|
|
547
556
|
<summary>Usage</summary>
|
package/README.zh-Hans.md
CHANGED
|
@@ -122,7 +122,7 @@ import "echarts";
|
|
|
122
122
|
```html
|
|
123
123
|
<script src="https://cdn.jsdelivr.net/npm/echarts@6.1.0"></script>
|
|
124
124
|
<script src="https://cdn.jsdelivr.net/npm/vue@3.5.41"></script>
|
|
125
|
-
<script src="https://cdn.jsdelivr.net/npm/vue-echarts@8.
|
|
125
|
+
<script src="https://cdn.jsdelivr.net/npm/vue-echarts@8.3.0"></script>
|
|
126
126
|
```
|
|
127
127
|
|
|
128
128
|
<!-- scripts:end -->
|
|
@@ -150,6 +150,8 @@ app.component('VChart', VueECharts)
|
|
|
150
150
|
|
|
151
151
|
要应用的主题。请参考 `echarts.init` 的 `theme` 参数。[前往 →](https://echarts.apache.org/zh/api.html#echarts.init)
|
|
152
152
|
|
|
153
|
+
ECharts 在切换主题时会重建模型。Vue ECharts 会重新应用最新的自动更新配置,但未受控的交互状态(如图例选择、数据缩放)可能重置。需要跨重建保留的状态应维护在 `option` 中。
|
|
154
|
+
|
|
153
155
|
传入空字符串可以在覆盖注入主题的同时使用 ECharts 默认主题。
|
|
154
156
|
|
|
155
157
|
Inject 键名:`THEME_KEY`。
|
|
@@ -160,9 +162,15 @@ app.component('VChart', VueECharts)
|
|
|
160
162
|
暂时移除该 prop 会暂停自动更新,之后的主题变更也不会让图表回退到初始 option。
|
|
161
163
|
|
|
162
164
|
#### 智能更新
|
|
163
|
-
|
|
165
|
+
|
|
166
|
+
自动 option、theme 和插槽变化会在 Vue 更新后合并处理。`clear()` 立即生效并取消已经排队的自动更新,后续变化仍可重新填充图表。
|
|
167
|
+
|
|
168
|
+
响应式更新描述完整配置。Vue ECharts 会在合并能够正确应用配置时保留现有模型,并在必要时通过重建清除旧配置。重建可能重置图例选择、数据缩放等交互状态。
|
|
169
|
+
|
|
170
|
+
- 如果提供了 `update-options`(或通过 inject 注入),Vue ECharts 会直接把它传给 `setOption`,不会执行智能计划。移除它之后,首次源 option 智能更新会重建一次,以建立可靠的结构基线。
|
|
171
|
+
- option 或主题提交失败会使结构基线失效。下一次智能更新会重建,避免依赖可能只完成了一部分的更新。
|
|
164
172
|
- 手动调用 `setOption`(仅当 `manual-update` 为 `true` 时可用)与原生 ECharts 保持一致,只使用本次调用传入的参数,重新初始化后不会保留这些调用的效果。
|
|
165
|
-
- 如果更新中有 graphic 元素使用 `$action`,`graphic` 会保留普通合并,让命令能够作用于现有元素树;无关组件的安全删除仍会使用 `replaceMerge
|
|
173
|
+
- 如果更新中有 graphic 元素使用 `$action`,`graphic` 会保留普通合并,让命令能够作用于现有元素树;无关组件的安全删除仍会使用 `replaceMerge`。需要完整重建的变更无法与这些命令一起应用。若需要完整快照语义,请直接描述更新后的 graphic 元素树,不使用 `$action` 命令。
|
|
166
174
|
- 其他情况下,Vue ECharts 会分析差异:组件删除、重排及匿名组件内部的属性删除会在 `replaceMerge` 能还原目标顺序时使用它;已按 ID 匹配的组件内部属性删除、`replaceMerge` 无法还原的身份顺序变化、新增或缩短的非组件数组、首次 ARIA 配置及其他高风险变更会退回 `notMerge: true`。
|
|
167
175
|
|
|
168
176
|
- `update-options: object`
|
|
@@ -540,6 +548,8 @@ import { GGroup, GRect, GText } from "vue-echarts/graphic";
|
|
|
540
548
|
> - 路径组件支持通过 `auto-batch` 启用 ZRender 的 Canvas 路径批处理。
|
|
541
549
|
> - 仅使用 graphic 插槽时可以省略 `option` prop。
|
|
542
550
|
> - `#graphic` 会覆盖 `option.graphic`。`manual-update` 模式下需调用 `chartRef.setOption(...)` 提交变更。
|
|
551
|
+
> - 包装组件和 Fragment 中的图形遵循实际渲染顺序。可合并的属性变化只更新变更节点,保留未变更元素及其正在运行的动画。删除字段、改变类型或树结构时,会重建 graphic 组件。
|
|
552
|
+
> - 仅 graphic 变化时,会在安全的情况下省略无关的源配置。显式指定 `notMerge` 或针对其他组件的 `replaceMerge` 时,仍会提交完整源配置。
|
|
543
553
|
|
|
544
554
|
<details>
|
|
545
555
|
<summary>用法示例</summary>
|
package/dist/graphic.d.ts
CHANGED
|
@@ -234,7 +234,7 @@ declare const shapeProps: {
|
|
|
234
234
|
};
|
|
235
235
|
type GraphicShapeProps = ExtractPublicPropTypes<typeof shapeProps>;
|
|
236
236
|
//#endregion
|
|
237
|
-
//#region src/graphic/
|
|
237
|
+
//#region src/graphic/component-type.d.ts
|
|
238
238
|
type GraphicComponentType = "group" | "rect" | "circle" | "ellipse" | "text" | "line" | "polyline" | "polygon" | "image" | "sector" | "ring" | "arc" | "bezierCurve";
|
|
239
239
|
//#endregion
|
|
240
240
|
//#region src/graphic/component-factory.d.ts
|
|
@@ -406,8 +406,7 @@ declare const componentProps: {
|
|
|
406
406
|
};
|
|
407
407
|
type NestedShapePropKey = "shape" | "shapeTransition";
|
|
408
408
|
type NestedStylePropKey = "style" | "styleTransition";
|
|
409
|
-
type
|
|
410
|
-
type SharedPropKey<T extends GraphicComponentType> = Exclude<Exclude<keyof typeof componentProps, SpecializedPropKey> | GraphicCommonPropKey, T extends "text" ? GraphicTextAttachmentPropKey : never>;
|
|
409
|
+
type SharedPropKey<T extends GraphicComponentType> = Exclude<GraphicCommonPropKey, T extends "text" ? GraphicTextAttachmentPropKey : never>;
|
|
411
410
|
type StylePropKey<T extends GraphicComponentType> = T extends "group" ? never : NestedStylePropKey | (T extends "text" ? GraphicTextCommonStyleKey : GraphicCommonStyleKey) | (T extends keyof typeof SHAPE_KEYS_BY_TYPE ? GraphicPathStyleKey : T extends "text" ? GraphicTextStyleKey : T extends "image" ? GraphicImageStyleKey : never);
|
|
412
411
|
type PathPropKey<T extends GraphicComponentType> = T extends keyof typeof SHAPE_KEYS_BY_TYPE ? NestedShapePropKey | GraphicPathPropKey | (typeof SHAPE_KEYS_BY_TYPE)[T][number] : never;
|
|
413
412
|
type GroupPropKey<T extends GraphicComponentType> = T extends "group" ? GraphicGroupPropKey : never;
|
package/dist/graphic.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { Teleport, defineComponent, getCurrentInstance, h, inject, onBeforeMount, onBeforeUnmount, onMounted, onScopeDispose, onUpdated, provide, shallowRef, watch } from "vue";
|
|
1
|
+
import { a as hasEventHandler, c as isIgnorableWatchChange, f as parseOnEvent, i as createEventInvoker, n as registerRuntime, p as warn$1, s as isBrowser, t as planUpdate } from "./update-CWPvYl2M.js";
|
|
2
|
+
import { Teleport, defineComponent, getCurrentInstance, h, inject, onBeforeMount, onBeforeUnmount, onMounted, onScopeDispose, onUpdated, provide, queuePostFlushCb, shallowRef, watch } from "vue";
|
|
3
3
|
import { use } from "echarts/core";
|
|
4
4
|
import { GraphicComponent } from "echarts/components";
|
|
5
5
|
const COMMON_PROP_KEYS = [
|
|
@@ -497,7 +497,6 @@ function buildOption(nodes, rootId) {
|
|
|
497
497
|
return { graphic: { elements: [{
|
|
498
498
|
type: "group",
|
|
499
499
|
id: rootId,
|
|
500
|
-
$action: "replace",
|
|
501
500
|
children: childrenOf(null) ?? []
|
|
502
501
|
}] } };
|
|
503
502
|
}
|
|
@@ -508,7 +507,41 @@ function createCollector(onFlush) {
|
|
|
508
507
|
const seenInPass = /* @__PURE__ */ new Map();
|
|
509
508
|
const warnedKeys = /* @__PURE__ */ new Set();
|
|
510
509
|
let order = 0;
|
|
510
|
+
let version = 0;
|
|
511
511
|
let pending = false;
|
|
512
|
+
let root;
|
|
513
|
+
let observer;
|
|
514
|
+
const byElement = /* @__PURE__ */ new WeakMap();
|
|
515
|
+
let orderedIds = [];
|
|
516
|
+
function syncOrder() {
|
|
517
|
+
if (!root) return false;
|
|
518
|
+
const ids = [];
|
|
519
|
+
const walker = root.ownerDocument.createTreeWalker(root, 1);
|
|
520
|
+
for (let element = walker.nextNode(); element; element = walker.nextNode()) {
|
|
521
|
+
const node = byElement.get(element);
|
|
522
|
+
if (node && nodes.get(node.id) === node) {
|
|
523
|
+
node.order = ids.length;
|
|
524
|
+
ids.push(node.id);
|
|
525
|
+
}
|
|
526
|
+
}
|
|
527
|
+
const changed = ids.length !== orderedIds.length || ids.some((id, index) => id !== orderedIds[index]);
|
|
528
|
+
orderedIds = ids;
|
|
529
|
+
return changed;
|
|
530
|
+
}
|
|
531
|
+
function setRoot(value) {
|
|
532
|
+
observer?.disconnect();
|
|
533
|
+
root = value;
|
|
534
|
+
orderedIds = [];
|
|
535
|
+
if (root) {
|
|
536
|
+
observer = new MutationObserver(() => {
|
|
537
|
+
if (syncOrder()) requestFlush();
|
|
538
|
+
});
|
|
539
|
+
observer.observe(root, {
|
|
540
|
+
childList: true,
|
|
541
|
+
subtree: true
|
|
542
|
+
});
|
|
543
|
+
}
|
|
544
|
+
}
|
|
512
545
|
function beginPass() {
|
|
513
546
|
order = 0;
|
|
514
547
|
seenInPass.clear();
|
|
@@ -525,14 +558,17 @@ function createCollector(onFlush) {
|
|
|
525
558
|
order = Math.max(order, nextOrder + 1);
|
|
526
559
|
const existing = nodes.get(node.id);
|
|
527
560
|
const sameSource = existing?.sourceId === node.sourceId;
|
|
528
|
-
const unchanged = sameSource && existing.type === node.type && existing.parentId === node.parentId && existing.props === node.props && existing.handlers === node.
|
|
561
|
+
const unchanged = sameSource && existing.type === node.type && existing.parentId === node.parentId && existing.props === node.props && isIgnorableWatchChange(existing.handlers, node.handlers) && existing.element === node.element && (node.element !== void 0 || existing.order === nextOrder);
|
|
529
562
|
seenInPass.set(node.id, node.sourceId);
|
|
530
563
|
if (unchanged) return;
|
|
531
|
-
|
|
564
|
+
const registered = {
|
|
532
565
|
...node,
|
|
533
566
|
handlerCache: sameSource ? existing?.handlerCache : void 0,
|
|
534
|
-
order: nextOrder
|
|
535
|
-
|
|
567
|
+
order: nextOrder,
|
|
568
|
+
version: ++version
|
|
569
|
+
};
|
|
570
|
+
nodes.set(node.id, registered);
|
|
571
|
+
if (node.element) byElement.set(node.element, registered);
|
|
536
572
|
requestFlush();
|
|
537
573
|
}
|
|
538
574
|
function unregister(id, sourceId) {
|
|
@@ -541,10 +577,12 @@ function createCollector(onFlush) {
|
|
|
541
577
|
nodes.delete(id);
|
|
542
578
|
requestFlush();
|
|
543
579
|
}
|
|
544
|
-
function requestFlush() {
|
|
580
|
+
function requestFlush(id, sourceId) {
|
|
581
|
+
const node = id === void 0 ? void 0 : nodes.get(id);
|
|
582
|
+
if (node && node.sourceId === sourceId) node.version = ++version;
|
|
545
583
|
if (pending) return;
|
|
546
584
|
pending = true;
|
|
547
|
-
|
|
585
|
+
queuePostFlushCb(() => {
|
|
548
586
|
if (!pending) return;
|
|
549
587
|
pending = false;
|
|
550
588
|
beginPass();
|
|
@@ -552,10 +590,17 @@ function createCollector(onFlush) {
|
|
|
552
590
|
});
|
|
553
591
|
}
|
|
554
592
|
function getNodes() {
|
|
555
|
-
|
|
593
|
+
syncOrder();
|
|
594
|
+
return root ? orderedIds.map((id) => nodes.get(id)) : nodes.values();
|
|
595
|
+
}
|
|
596
|
+
function dispose() {
|
|
597
|
+
cancelPendingFlush();
|
|
598
|
+
setRoot(void 0);
|
|
599
|
+
nodes.clear();
|
|
556
600
|
}
|
|
557
601
|
function cancelPendingFlush() {
|
|
558
602
|
pending = false;
|
|
603
|
+
syncOrder();
|
|
559
604
|
beginPass();
|
|
560
605
|
}
|
|
561
606
|
return {
|
|
@@ -565,87 +610,15 @@ function createCollector(onFlush) {
|
|
|
565
610
|
warn,
|
|
566
611
|
getNodes,
|
|
567
612
|
requestFlush,
|
|
568
|
-
cancelPendingFlush
|
|
613
|
+
cancelPendingFlush,
|
|
614
|
+
setRoot,
|
|
615
|
+
dispose
|
|
569
616
|
};
|
|
570
617
|
}
|
|
571
618
|
//#endregion
|
|
572
619
|
//#region src/graphic/context.ts
|
|
573
620
|
const GRAPHIC_COLLECTOR_KEY = Symbol("vue-echarts:graphic-collector");
|
|
574
621
|
const GRAPHIC_PARENT_ID_KEY = Symbol("vue-echarts:graphic-parent-id");
|
|
575
|
-
const GRAPHIC_ORDER_KEY = Symbol("vue-echarts:graphic-order");
|
|
576
|
-
//#endregion
|
|
577
|
-
//#region src/graphic/identity.ts
|
|
578
|
-
function toOrderKey(key) {
|
|
579
|
-
return typeof key === "string" ? `key:${key}` : key ?? void 0;
|
|
580
|
-
}
|
|
581
|
-
function resolveIdentity(propsId, vnodeKey, uid) {
|
|
582
|
-
if (propsId != null) {
|
|
583
|
-
const id = String(propsId);
|
|
584
|
-
return {
|
|
585
|
-
id,
|
|
586
|
-
orderKey: `id:${id}`
|
|
587
|
-
};
|
|
588
|
-
}
|
|
589
|
-
const orderKey = toOrderKey(vnodeKey);
|
|
590
|
-
if (orderKey !== void 0) return {
|
|
591
|
-
id: typeof vnodeKey === "string" ? vnodeKey : `__ve_graphic_${uid}`,
|
|
592
|
-
orderKey
|
|
593
|
-
};
|
|
594
|
-
return { id: `__ve_graphic_${uid}` };
|
|
595
|
-
}
|
|
596
|
-
function resolveOrderKey(propsId, vnodeKey) {
|
|
597
|
-
if (propsId != null) return `id:${String(propsId)}`;
|
|
598
|
-
return toOrderKey(vnodeKey) ?? null;
|
|
599
|
-
}
|
|
600
|
-
//#endregion
|
|
601
|
-
//#region src/graphic/marker.ts
|
|
602
|
-
const GRAPHIC_COMPONENT_MARKER = Symbol("vue-echarts:graphic-component");
|
|
603
|
-
//#endregion
|
|
604
|
-
//#region src/graphic/order.ts
|
|
605
|
-
function isGraphic(vnode) {
|
|
606
|
-
const type = vnode.type;
|
|
607
|
-
if (!type || typeof type !== "object") return false;
|
|
608
|
-
return typeof type[GRAPHIC_COMPONENT_MARKER] === "string";
|
|
609
|
-
}
|
|
610
|
-
function collect(value, orderMap, order) {
|
|
611
|
-
if (Array.isArray(value)) {
|
|
612
|
-
for (const child of value) order = collect(child, orderMap, order);
|
|
613
|
-
return order;
|
|
614
|
-
}
|
|
615
|
-
if (!value || typeof value !== "object") return order;
|
|
616
|
-
const vnode = value;
|
|
617
|
-
const children = vnode.children;
|
|
618
|
-
const graphic = isGraphic(vnode);
|
|
619
|
-
const type = typeof vnode.type;
|
|
620
|
-
const opaqueComponent = !Array.isArray(children) && (type === "object" || type === "function");
|
|
621
|
-
const props = vnode.props;
|
|
622
|
-
const identity = graphic || opaqueComponent ? resolveOrderKey(props?.id, vnode.key) : null;
|
|
623
|
-
if (identity !== null) orderMap.set(identity, order);
|
|
624
|
-
if (graphic) return order + 1;
|
|
625
|
-
if (identity !== null) order++;
|
|
626
|
-
if (Array.isArray(children)) for (const child of children) order = collect(child, orderMap, order);
|
|
627
|
-
return order;
|
|
628
|
-
}
|
|
629
|
-
function isSameOrder(current, next) {
|
|
630
|
-
if (current.size !== next.size) return false;
|
|
631
|
-
for (const [key, order] of current) if (next.get(key) !== order) return false;
|
|
632
|
-
return true;
|
|
633
|
-
}
|
|
634
|
-
function createOrderTracker() {
|
|
635
|
-
let current = /* @__PURE__ */ new Map();
|
|
636
|
-
const ref = shallowRef(current);
|
|
637
|
-
return {
|
|
638
|
-
ref,
|
|
639
|
-
update(value) {
|
|
640
|
-
const next = /* @__PURE__ */ new Map();
|
|
641
|
-
collect(value, next, 0);
|
|
642
|
-
if (!isSameOrder(current, next)) {
|
|
643
|
-
current = next;
|
|
644
|
-
ref.value = current;
|
|
645
|
-
}
|
|
646
|
-
}
|
|
647
|
-
};
|
|
648
|
-
}
|
|
649
622
|
//#endregion
|
|
650
623
|
//#region src/graphic/mount.ts
|
|
651
624
|
const GraphicMount = defineComponent({
|
|
@@ -661,29 +634,30 @@ const GraphicMount = defineComponent({
|
|
|
661
634
|
const detachedRoot = shallowRef();
|
|
662
635
|
const contentReady = shallowRef(isBrowser() && !instance.vnode.el);
|
|
663
636
|
const parentId = shallowRef(null);
|
|
664
|
-
const order = createOrderTracker();
|
|
665
637
|
onBeforeMount(() => {
|
|
666
638
|
const host = instance.parent?.subTree.el;
|
|
667
639
|
if (host) {
|
|
668
640
|
const target = host.ownerDocument.createElement("div");
|
|
669
641
|
host.appendChild(target);
|
|
670
642
|
detachedRoot.value = target;
|
|
643
|
+
collector.setRoot(target);
|
|
671
644
|
}
|
|
672
645
|
});
|
|
673
646
|
onMounted(() => {
|
|
674
647
|
const ownerDocument = instance.vnode.el.ownerDocument;
|
|
675
648
|
const target = detachedRoot.value;
|
|
676
649
|
target?.remove();
|
|
677
|
-
if (target?.ownerDocument !== ownerDocument)
|
|
650
|
+
if (target?.ownerDocument !== ownerDocument) {
|
|
651
|
+
detachedRoot.value = ownerDocument.createElement("div");
|
|
652
|
+
collector.setRoot(detachedRoot.value);
|
|
653
|
+
}
|
|
678
654
|
contentReady.value = true;
|
|
679
655
|
});
|
|
680
656
|
provide(GRAPHIC_COLLECTOR_KEY, collector);
|
|
681
657
|
provide(GRAPHIC_PARENT_ID_KEY, parentId);
|
|
682
|
-
provide(GRAPHIC_ORDER_KEY, order.ref);
|
|
683
658
|
return () => {
|
|
684
659
|
beginPass();
|
|
685
660
|
const content = slots.default();
|
|
686
|
-
order.update(content);
|
|
687
661
|
const target = detachedRoot.value;
|
|
688
662
|
return h(Teleport, {
|
|
689
663
|
to: target ?? "body",
|
|
@@ -701,14 +675,19 @@ function registerExtension() {
|
|
|
701
675
|
const { slots, manualUpdate, requestUpdate } = ctx;
|
|
702
676
|
const collector = createCollector(handleFlush);
|
|
703
677
|
let hasGraphicSlot = Boolean(slots.graphic);
|
|
678
|
+
let signature;
|
|
679
|
+
let versions = /* @__PURE__ */ new Map();
|
|
704
680
|
function handleFlush() {
|
|
705
681
|
if (manualUpdate.value) {
|
|
682
|
+
const nodes = Array.from(collector.getNodes());
|
|
683
|
+
const changed = !slots.graphic || nodes.length !== versions.size || nodes.some((node) => versions.get(node.id) !== node.version);
|
|
684
|
+
if (!signature || !changed) return;
|
|
706
685
|
collector.warn("`#graphic` slot updates are ignored when `manual-update` is `true`.", "manual-update-graphic");
|
|
707
686
|
return;
|
|
708
687
|
}
|
|
709
688
|
requestUpdate();
|
|
710
689
|
}
|
|
711
|
-
onScopeDispose(collector.
|
|
690
|
+
onScopeDispose(collector.dispose);
|
|
712
691
|
onUpdated(() => {
|
|
713
692
|
const nextHasGraphicSlot = Boolean(slots.graphic);
|
|
714
693
|
if (nextHasGraphicSlot === hasGraphicSlot) return;
|
|
@@ -717,15 +696,44 @@ function registerExtension() {
|
|
|
717
696
|
handleFlush();
|
|
718
697
|
});
|
|
719
698
|
return {
|
|
720
|
-
|
|
699
|
+
cancelPendingFlush: collector.cancelPendingFlush,
|
|
700
|
+
prepare(option, reset) {
|
|
721
701
|
hasGraphicSlot = Boolean(slots.graphic);
|
|
722
|
-
if (!hasGraphicSlot) return option;
|
|
723
|
-
if (option.graphic) collector.warn("`#graphic` slot is provided, so `option.graphic` is ignored. Remove one of them to avoid ambiguity.", "option-graphic-override");
|
|
724
|
-
const nextOption = buildOption(collector.getNodes(), ROOT_ID);
|
|
725
702
|
collector.cancelPendingFlush();
|
|
703
|
+
if (!hasGraphicSlot) return {
|
|
704
|
+
option,
|
|
705
|
+
replace: false,
|
|
706
|
+
commit: () => {
|
|
707
|
+
signature = void 0;
|
|
708
|
+
versions.clear();
|
|
709
|
+
}
|
|
710
|
+
};
|
|
711
|
+
if (option.graphic) collector.warn("`#graphic` slot is provided, so `option.graphic` is ignored. Remove one of them to avoid ambiguity.", "option-graphic-override");
|
|
712
|
+
const nodes = Array.from(collector.getNodes());
|
|
713
|
+
const nextOption = buildOption(nodes, ROOT_ID);
|
|
714
|
+
const planned = planUpdate(signature, nextOption);
|
|
715
|
+
const replace = reset || !signature || planned.plan.notMerge || Boolean(planned.plan.replaceMerge?.length);
|
|
716
|
+
const nextVersions = new Map(nodes.map((node) => [node.id, node.version]));
|
|
717
|
+
const elements = [];
|
|
718
|
+
function collectChanges(element, parentId) {
|
|
719
|
+
const { children, ...props } = element;
|
|
720
|
+
if (nextVersions.has(element.id) && nextVersions.get(element.id) !== versions.get(element.id)) elements.push({
|
|
721
|
+
...props,
|
|
722
|
+
parentId
|
|
723
|
+
});
|
|
724
|
+
children?.forEach((child) => collectChanges(child, element.id));
|
|
725
|
+
}
|
|
726
|
+
if (!replace) nextOption.graphic.elements.forEach((element) => collectChanges(element));
|
|
727
|
+
const patched = { ...option };
|
|
728
|
+
delete patched.graphic;
|
|
729
|
+
if (replace || elements.length) patched.graphic = replace ? nextOption.graphic : { elements };
|
|
726
730
|
return {
|
|
727
|
-
|
|
728
|
-
|
|
731
|
+
option: patched,
|
|
732
|
+
replace,
|
|
733
|
+
commit: () => {
|
|
734
|
+
signature = planned.signature;
|
|
735
|
+
versions = nextVersions;
|
|
736
|
+
}
|
|
729
737
|
};
|
|
730
738
|
},
|
|
731
739
|
render() {
|
|
@@ -736,67 +744,91 @@ function registerExtension() {
|
|
|
736
744
|
});
|
|
737
745
|
}
|
|
738
746
|
//#endregion
|
|
747
|
+
//#region src/graphic/identity.ts
|
|
748
|
+
function resolveIdentity(propsId, vnodeKey, uid) {
|
|
749
|
+
if (propsId != null) return String(propsId);
|
|
750
|
+
return typeof vnodeKey === "string" ? vnodeKey : `__ve_graphic_${uid}`;
|
|
751
|
+
}
|
|
752
|
+
//#endregion
|
|
739
753
|
//#region src/graphic/component-factory.ts
|
|
740
|
-
const
|
|
754
|
+
const componentProps = {
|
|
741
755
|
...commonProps,
|
|
742
|
-
...shapeProps
|
|
743
|
-
width: textPropOverrides.width
|
|
756
|
+
...shapeProps
|
|
744
757
|
};
|
|
758
|
+
function getRuntimeProps(type) {
|
|
759
|
+
const keys = COMMON_PROP_KEYS.filter((key) => type !== "text" || key !== "textContent" && key !== "textConfig");
|
|
760
|
+
if (type === "group") keys.push(...GROUP_PROP_KEYS);
|
|
761
|
+
else {
|
|
762
|
+
const shapeKeys = SHAPE_KEYS_BY_TYPE[type];
|
|
763
|
+
const styleKeys = shapeKeys ? PATH_STYLE_KEYS : STYLE_KEYS_BY_TYPE[type];
|
|
764
|
+
const commonStyleKeys = type === "text" ? TEXT_COMMON_STYLE_KEYS : COMMON_STYLE_KEYS;
|
|
765
|
+
keys.push("style", "styleTransition", ...DISPLAYABLE_PROP_KEYS, ...commonStyleKeys, ...styleKeys);
|
|
766
|
+
if (shapeKeys) keys.push("shape", "shapeTransition", ...PATH_PROP_KEYS, ...shapeKeys);
|
|
767
|
+
}
|
|
768
|
+
const definitions = type === "text" ? {
|
|
769
|
+
...componentProps,
|
|
770
|
+
...textPropOverrides
|
|
771
|
+
} : {
|
|
772
|
+
...componentProps,
|
|
773
|
+
r: type === "rect" ? componentProps.r : Number
|
|
774
|
+
};
|
|
775
|
+
return Object.fromEntries(keys.map((key) => [key, definitions[key]]));
|
|
776
|
+
}
|
|
745
777
|
/* @__NO_SIDE_EFFECTS__ */
|
|
746
778
|
function createComponent(name, type) {
|
|
747
|
-
|
|
779
|
+
return defineComponent({
|
|
748
780
|
name,
|
|
749
781
|
inheritAttrs: false,
|
|
750
|
-
props:
|
|
782
|
+
props: getRuntimeProps(type),
|
|
751
783
|
emits: {},
|
|
752
784
|
setup(props, { attrs, slots }) {
|
|
753
785
|
const instance = getCurrentInstance();
|
|
754
786
|
const collector = inject(GRAPHIC_COLLECTOR_KEY, null);
|
|
755
787
|
const parentIdRef = inject(GRAPHIC_PARENT_ID_KEY, null);
|
|
756
|
-
const parentOrderRef = inject(GRAPHIC_ORDER_KEY, null);
|
|
757
788
|
if (!collector) {
|
|
758
789
|
warn$1(`\`${name}\` must be used inside \`#graphic\` slot.`);
|
|
759
790
|
return () => null;
|
|
760
791
|
}
|
|
761
792
|
const { register: registerNode, unregister, requestFlush } = collector;
|
|
762
793
|
let currentId = null;
|
|
763
|
-
|
|
794
|
+
let element;
|
|
795
|
+
watch([props, () => attrs], () => requestFlush(currentId ?? void 0, instance.uid), { deep: true });
|
|
764
796
|
function register() {
|
|
765
|
-
const
|
|
797
|
+
const id = resolveIdentity(props.id, instance.vnode.key, instance.uid);
|
|
766
798
|
if (currentId !== null && currentId !== id) unregister(currentId, instance.uid);
|
|
767
799
|
currentId = id;
|
|
768
|
-
registerNode({
|
|
800
|
+
if (element) registerNode({
|
|
769
801
|
id,
|
|
770
802
|
type,
|
|
771
803
|
parentId: parentIdRef.value,
|
|
772
|
-
|
|
804
|
+
element,
|
|
773
805
|
props,
|
|
774
|
-
handlers: attrs,
|
|
806
|
+
handlers: { ...attrs },
|
|
775
807
|
sourceId: instance.uid
|
|
776
808
|
});
|
|
777
809
|
return id;
|
|
778
810
|
}
|
|
811
|
+
const setElement = (value) => {
|
|
812
|
+
if (value === element) return;
|
|
813
|
+
element = value ?? void 0;
|
|
814
|
+
if (element) register();
|
|
815
|
+
};
|
|
779
816
|
onBeforeUnmount(() => unregister(currentId, instance.uid));
|
|
780
817
|
if (type === "group") {
|
|
781
818
|
const providedParent = shallowRef(null);
|
|
782
|
-
const childOrder = createOrderTracker();
|
|
783
819
|
provide(GRAPHIC_PARENT_ID_KEY, providedParent);
|
|
784
|
-
provide(GRAPHIC_ORDER_KEY, childOrder.ref);
|
|
785
820
|
return () => {
|
|
786
821
|
providedParent.value = register();
|
|
787
|
-
const content = slots.default?.() ??
|
|
788
|
-
|
|
789
|
-
return content;
|
|
822
|
+
const content = slots.default?.() ?? [];
|
|
823
|
+
return h("div", { ref: setElement }, content);
|
|
790
824
|
};
|
|
791
825
|
}
|
|
792
826
|
return () => {
|
|
793
827
|
register();
|
|
794
|
-
return
|
|
828
|
+
return h("div", { ref: setElement });
|
|
795
829
|
};
|
|
796
830
|
}
|
|
797
831
|
});
|
|
798
|
-
component[GRAPHIC_COMPONENT_MARKER] = type;
|
|
799
|
-
return component;
|
|
800
832
|
}
|
|
801
833
|
//#endregion
|
|
802
834
|
//#region src/graphic/components.ts
|