@gravity-ui/graph
Version:
Modern graph editor component
104 lines (103 loc) • 2.96 kB
JavaScript
import { signal } from "@preact/signals-core";
import { ESchedulerPriority } from "../lib";
import { Component } from "../lib/Component";
import { Emitter } from "../utils/Emitter";
import { throttle } from "../utils/functions";
export class Layers extends Emitter {
constructor($root) {
super();
this.$root = $root;
this.attached = false;
this.rootSize = signal({ width: 0, height: 0, dpr: globalThis.devicePixelRatio || 1 });
this.layers = new Set();
this.resizeObserver = new ResizeObserver(() => {
this.handleRootResize();
});
this.handleRootResize = throttle(() => {
this.updateSize();
}, {
priority: ESchedulerPriority.LOWEST,
frameInterval: 1,
});
this.updateSize = () => {
if (!this.$root) {
return;
}
this.rootSize.value = {
width: this.$root.clientWidth,
height: this.$root.clientHeight,
dpr: this.getDPR(),
};
this.emit("update-size", this.getRootSize());
};
}
getDPR() {
return globalThis.devicePixelRatio || 1;
}
createLayer(layerCtor, props) {
const layer = Component.mount(layerCtor, {
root: this.$root,
...props,
});
this.layers.add(layer);
if (this.attached) {
layer.attachLayer(this.$root);
}
return layer;
}
detachLayer(layer) {
this.layers.delete(layer);
layer.detachLayer();
}
getRootSize() {
return this.rootSize.value;
}
getLayers() {
return Array.from(this.layers);
}
attach(root = this.$root) {
this.$root = root;
this.layers.forEach((layer) => {
layer.attachLayer(this.$root);
});
}
start(root = this.$root) {
if (this.attached) {
return;
}
this.attach(root);
if (!this.$root) {
throw new Error("Root not specified");
}
this.updateSize();
this.resizeObserver.observe(this.$root, { box: "border-box" });
window.addEventListener("resize", this.handleRootResize);
this.attached = true;
}
detach(full = false) {
this.layers.forEach((layer) => {
layer.detachLayer();
});
this.attached = false;
window.removeEventListener("resize", this.handleRootResize);
this.handleRootResize.cancel();
this.resizeObserver.disconnect();
if (full) {
this.$root = undefined;
}
}
unmount() {
this.detach(true);
this.destroy();
}
destroy() {
this.detach();
this.destroyLayers();
this.off();
}
destroyLayers() {
this.layers.forEach((layer) => {
Component.unmount(layer);
});
}
}