UNPKG

@gravity-ui/graph

Version:

Modern graph editor component

104 lines (103 loc) 2.96 kB
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); }); } }