This repository has been archived by the owner on May 15, 2024. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 7
/
Copy pathwrapper.ts
111 lines (96 loc) · 4.03 KB
/
wrapper.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
import { createRendererForStage } from "./runtime";
import {
defineComponent,
Fragment,
watchEffect,
h,
onMounted,
Ref,
ref,
getCurrentInstance,
RootRenderFunction,
} from "@vue/runtime-core";
import { Stage } from "tree2d";
import { EventHelpers, setupEvents } from "./events";
import { Root } from "./runtime/nodes/Root";
import { nextTick } from "vue";
export type VugelStage = Stage & { eventHelpers: EventHelpers };
export const Vugel = defineComponent({
props: {
settings: { type: Object },
position: { type: String, default: "relative" },
},
setup(props, setupContext) {
const elRef: Ref<HTMLCanvasElement | undefined> = ref();
const maxWidth = ref(4096);
const maxHeight = ref(4096);
const vugelComponentInstance = getCurrentInstance()!;
onMounted(() => {
let rendered = false;
let vugelRenderer: RootRenderFunction;
let stage: VugelStage;
let stageRoot: Root;
watchEffect(() => {
if (!rendered && elRef.value) {
rendered = true;
stage = new Stage(elRef.value, { ...props.settings }) as VugelStage;
stage.eventHelpers = setupEvents(props.settings?.eventsTarget || elRef.value, stage);
vugelRenderer = createRendererForStage(stage);
stageRoot = new Root(stage, stage.root);
// Auto-inherit dimensions.
stageRoot["func-w"] = (w: number) => w;
stageRoot["func-h"] = (w: number, h: number) => h;
// Keep correct aspect-ratio issues when the page is zoomed out.
const maxTextureSize = stage.getMaxTextureSize();
maxWidth.value = maxTextureSize / stage.pixelRatio;
maxHeight.value = maxTextureSize / stage.pixelRatio;
}
const defaultSlot = setupContext.slots.default;
if (defaultSlot) {
// We must wait until nextTick to prevent interference in the effect queue.
nextTick().then(() => {
const node = h(Connector, defaultSlot);
vugelRenderer(node, stageRoot);
});
} else {
console.warn("No default slot is defined");
}
});
});
/**
* Since vugel uses its own renderer, the ancestor vue's appContext, root and provides would normally be lost in
* the vugel components.
*
* We can fix this by overriding the component's parent, root, appContext and provides before rendering the slot
* contents.
*/
const Connector = defineComponent({
setup(props, setupContext) {
const instance = getCurrentInstance()!;
// @see runtime-core createComponentInstance
instance.parent = vugelComponentInstance;
instance.appContext = vugelComponentInstance.appContext;
instance.root = vugelComponentInstance.root;
(instance as any).provides = (vugelComponentInstance as any).provides;
const defaultSlot = setupContext.slots.default!;
return () => h(Fragment, defaultSlot());
},
});
// We need to use a wrapper for flexible size layouting to work with tree2d pixelRatio canvas auto-resizing.
return () =>
h(
"div",
{
class: "custom-renderer-wrapper",
style: { position: props.position, maxWidth: maxWidth.value, maxHeight: maxHeight.value },
},
[
h("canvas", {
class: "custom-renderer",
style: { position: "absolute", width: "100%", height: "100%" },
ref: elRef,
}),
],
);
},
});