cytoscape-dom-node 1.3.0 → 2.0.1
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/LICENSE +1 -1
- package/README.md +92 -34
- package/dist/index.cjs +229 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.mts +94 -0
- package/dist/index.d.ts +94 -0
- package/dist/index.global.js +225 -0
- package/dist/index.global.js.map +1 -0
- package/dist/index.mjs +204 -0
- package/dist/index.mjs.map +1 -0
- package/package.json +45 -7
- package/src/index.js +1 -150
- package/demo/LICENSE +0 -21
- package/demo/Makefile +0 -18
- package/demo/package-lock.json +0 -5941
- package/demo/package.json +0 -25
- package/demo/public/index.css +0 -26
- package/demo/public/index.html +0 -18
- package/demo/public/snapshots.html +0 -32
- package/demo/src/index.js +0 -109
- package/demo/webpack.config.js +0 -41
- package/gruntfile.js +0 -20
|
@@ -0,0 +1,225 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var cytoscapeDomNode = (() => {
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
7
|
+
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
8
|
+
var __export = (target, all) => {
|
|
9
|
+
for (var name in all)
|
|
10
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
11
|
+
};
|
|
12
|
+
var __copyProps = (to, from, except, desc) => {
|
|
13
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
14
|
+
for (let key of __getOwnPropNames(from))
|
|
15
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
16
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
17
|
+
}
|
|
18
|
+
return to;
|
|
19
|
+
};
|
|
20
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
21
|
+
var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
22
|
+
|
|
23
|
+
// src/index.ts
|
|
24
|
+
var index_exports = {};
|
|
25
|
+
__export(index_exports, {
|
|
26
|
+
CytoscapeDomNode: () => DomNodeRenderer,
|
|
27
|
+
DomNodeRenderer: () => DomNodeRenderer,
|
|
28
|
+
default: () => register
|
|
29
|
+
});
|
|
30
|
+
var DEFAULT_Z_INDEX = "10";
|
|
31
|
+
var ACTIVE_Z_INDEX = "11";
|
|
32
|
+
var SELECTED_CLASS_NAME = "selected";
|
|
33
|
+
var DomNodeRenderer = class {
|
|
34
|
+
constructor(cy, options = {}) {
|
|
35
|
+
__publicField(this, "cy");
|
|
36
|
+
__publicField(this, "nodeElements", /* @__PURE__ */ new Map());
|
|
37
|
+
__publicField(this, "resizeObserver");
|
|
38
|
+
__publicField(this, "container");
|
|
39
|
+
__publicField(this, "handleNodeAdd", (event) => {
|
|
40
|
+
this.addNode(event.target);
|
|
41
|
+
});
|
|
42
|
+
__publicField(this, "handleNodeRemove", (event) => {
|
|
43
|
+
this.removeNode(event.target);
|
|
44
|
+
});
|
|
45
|
+
__publicField(this, "handleNodePosition", (event) => {
|
|
46
|
+
this.syncNodePosition(event.target);
|
|
47
|
+
});
|
|
48
|
+
__publicField(this, "handleNodeState", (event) => {
|
|
49
|
+
this.syncNodeState(event.target);
|
|
50
|
+
});
|
|
51
|
+
__publicField(this, "handleViewport", () => {
|
|
52
|
+
this.syncViewport();
|
|
53
|
+
});
|
|
54
|
+
this.cy = cy;
|
|
55
|
+
this.container = resolveDomContainer(cy, options);
|
|
56
|
+
this.resizeObserver = new (resolveResizeObserver(options))((entries) => {
|
|
57
|
+
for (const entry of entries) {
|
|
58
|
+
this.syncNodeSize(entry.target);
|
|
59
|
+
}
|
|
60
|
+
});
|
|
61
|
+
this.bindEvents();
|
|
62
|
+
cy.nodes().forEach((node) => {
|
|
63
|
+
this.addNode(node);
|
|
64
|
+
});
|
|
65
|
+
this.syncViewport();
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Return the DOM element that backs a Cytoscape node id.
|
|
69
|
+
*/
|
|
70
|
+
nodeDom(id) {
|
|
71
|
+
return this.nodeElements.get(id);
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* @deprecated Use {@link nodeDom}.
|
|
75
|
+
*/
|
|
76
|
+
node_dom(id) {
|
|
77
|
+
return this.nodeDom(id);
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Remove event handlers and disconnect resize observation.
|
|
81
|
+
*/
|
|
82
|
+
destroy() {
|
|
83
|
+
this.cy.off("add", "node", this.handleNodeAdd);
|
|
84
|
+
this.cy.off("remove", "node", this.handleNodeRemove);
|
|
85
|
+
this.cy.off("pan zoom", this.handleViewport);
|
|
86
|
+
this.cy.off("position bounds", "node", this.handleNodePosition);
|
|
87
|
+
this.cy.off("select unselect grab free", "node", this.handleNodeState);
|
|
88
|
+
this.resizeObserver.disconnect();
|
|
89
|
+
this.nodeElements.clear();
|
|
90
|
+
}
|
|
91
|
+
bindEvents() {
|
|
92
|
+
this.cy.on("add", "node", this.handleNodeAdd);
|
|
93
|
+
this.cy.on("remove", "node", this.handleNodeRemove);
|
|
94
|
+
this.cy.on("pan zoom", this.handleViewport);
|
|
95
|
+
this.cy.on("position bounds", "node", this.handleNodePosition);
|
|
96
|
+
this.cy.on("select unselect grab free", "node", this.handleNodeState);
|
|
97
|
+
}
|
|
98
|
+
addNode(node) {
|
|
99
|
+
const data = node.data();
|
|
100
|
+
const element = data.dom;
|
|
101
|
+
if (!element) {
|
|
102
|
+
return;
|
|
103
|
+
}
|
|
104
|
+
const nodeId = node.id();
|
|
105
|
+
const shouldAppend = data.skipNodeAppend !== true && data.skip_node_append !== true;
|
|
106
|
+
if (shouldAppend && element.parentNode !== this.container) {
|
|
107
|
+
this.container.appendChild(element);
|
|
108
|
+
}
|
|
109
|
+
element.__cy_id = nodeId;
|
|
110
|
+
this.nodeElements.set(nodeId, element);
|
|
111
|
+
this.resizeObserver.observe(element);
|
|
112
|
+
this.syncNodeSize(element);
|
|
113
|
+
this.syncNodePosition(node);
|
|
114
|
+
this.syncNodeState(node);
|
|
115
|
+
}
|
|
116
|
+
removeNode(node) {
|
|
117
|
+
const element = this.nodeElements.get(node.id());
|
|
118
|
+
if (!element) {
|
|
119
|
+
return;
|
|
120
|
+
}
|
|
121
|
+
this.resizeObserver.unobserve(element);
|
|
122
|
+
delete element.__cy_id;
|
|
123
|
+
this.nodeElements.delete(node.id());
|
|
124
|
+
}
|
|
125
|
+
syncViewport() {
|
|
126
|
+
const pan = this.cy.pan();
|
|
127
|
+
const zoom = this.cy.zoom();
|
|
128
|
+
const transform = `translate(${String(pan.x)}px, ${String(
|
|
129
|
+
pan.y
|
|
130
|
+
)}px) scale(${String(zoom)})`;
|
|
131
|
+
setMsTransform(this.container, transform);
|
|
132
|
+
this.container.style.transform = transform;
|
|
133
|
+
}
|
|
134
|
+
syncNodeSize(element) {
|
|
135
|
+
if (!element.__cy_id) {
|
|
136
|
+
return;
|
|
137
|
+
}
|
|
138
|
+
const node = this.cy.getElementById(element.__cy_id);
|
|
139
|
+
if (node.empty()) {
|
|
140
|
+
return;
|
|
141
|
+
}
|
|
142
|
+
node.style({
|
|
143
|
+
height: element.offsetHeight,
|
|
144
|
+
shape: "rectangle",
|
|
145
|
+
width: element.offsetWidth
|
|
146
|
+
});
|
|
147
|
+
}
|
|
148
|
+
syncNodePosition(node) {
|
|
149
|
+
const element = this.nodeElements.get(node.id());
|
|
150
|
+
if (!element) {
|
|
151
|
+
return;
|
|
152
|
+
}
|
|
153
|
+
const position = node.position();
|
|
154
|
+
const transform = `translate(-50%, -50%) translate(${position.x.toFixed(
|
|
155
|
+
2
|
|
156
|
+
)}px, ${position.y.toFixed(2)}px)`;
|
|
157
|
+
element.style.webkitTransform = transform;
|
|
158
|
+
setMsTransform(element, transform);
|
|
159
|
+
element.style.transform = transform;
|
|
160
|
+
element.style.display = "inline";
|
|
161
|
+
element.style.position = "absolute";
|
|
162
|
+
}
|
|
163
|
+
syncNodeState(node) {
|
|
164
|
+
const element = this.nodeElements.get(node.id());
|
|
165
|
+
if (!element) {
|
|
166
|
+
return;
|
|
167
|
+
}
|
|
168
|
+
const isSelected = node.selected();
|
|
169
|
+
const isActive = isSelected || node.grabbed();
|
|
170
|
+
element.classList.toggle(SELECTED_CLASS_NAME, isSelected);
|
|
171
|
+
element.style.zIndex = isActive ? ACTIVE_Z_INDEX : DEFAULT_Z_INDEX;
|
|
172
|
+
}
|
|
173
|
+
};
|
|
174
|
+
function register(cytoscapeInstance) {
|
|
175
|
+
if (!cytoscapeInstance) {
|
|
176
|
+
return;
|
|
177
|
+
}
|
|
178
|
+
cytoscapeInstance(
|
|
179
|
+
"core",
|
|
180
|
+
"domNode",
|
|
181
|
+
function domNode(options) {
|
|
182
|
+
return new DomNodeRenderer(this, options);
|
|
183
|
+
}
|
|
184
|
+
);
|
|
185
|
+
}
|
|
186
|
+
function resolveDomContainer(cy, options) {
|
|
187
|
+
var _a;
|
|
188
|
+
const providedContainer = (_a = options.domContainer) != null ? _a : options.dom_container;
|
|
189
|
+
if (providedContainer) {
|
|
190
|
+
return providedContainer;
|
|
191
|
+
}
|
|
192
|
+
const cyContainer = cy.container();
|
|
193
|
+
const canvas = cyContainer == null ? void 0 : cyContainer.querySelector("canvas");
|
|
194
|
+
if (!(canvas == null ? void 0 : canvas.parentNode)) {
|
|
195
|
+
throw new Error(
|
|
196
|
+
"cytoscape-dom-node requires a Cytoscape container with a canvas, or a domContainer option."
|
|
197
|
+
);
|
|
198
|
+
}
|
|
199
|
+
const container = document.createElement("div");
|
|
200
|
+
container.style.position = "absolute";
|
|
201
|
+
container.style.transformOrigin = "0 0";
|
|
202
|
+
container.style.zIndex = DEFAULT_Z_INDEX;
|
|
203
|
+
canvas.parentNode.appendChild(container);
|
|
204
|
+
return container;
|
|
205
|
+
}
|
|
206
|
+
function resolveResizeObserver(options) {
|
|
207
|
+
var _a;
|
|
208
|
+
const ResizeObserverClass = (_a = options.resizeObserver) != null ? _a : globalThis.ResizeObserver;
|
|
209
|
+
if (!ResizeObserverClass) {
|
|
210
|
+
throw new Error(
|
|
211
|
+
"cytoscape-dom-node requires ResizeObserver. Provide a polyfill or pass resizeObserver."
|
|
212
|
+
);
|
|
213
|
+
}
|
|
214
|
+
return ResizeObserverClass;
|
|
215
|
+
}
|
|
216
|
+
function setMsTransform(element, transform) {
|
|
217
|
+
element.style.msTransform = transform;
|
|
218
|
+
}
|
|
219
|
+
var globalCytoscape = globalThis;
|
|
220
|
+
if (globalCytoscape.cytoscape) {
|
|
221
|
+
register(globalCytoscape.cytoscape);
|
|
222
|
+
}
|
|
223
|
+
return __toCommonJS(index_exports);
|
|
224
|
+
})();
|
|
225
|
+
//# sourceMappingURL=index.global.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/index.ts"],"sourcesContent":["/**\n * Index.\n *\n * @packageDocumentation\n */\n\nimport type cytoscape from \"cytoscape\";\n\nconst DEFAULT_Z_INDEX = \"10\";\nconst ACTIVE_Z_INDEX = \"11\";\nconst SELECTED_CLASS_NAME = \"selected\";\n\ntype CytoscapeRegistry = typeof cytoscape;\n\n/**\n * Constructor shape for ResizeObserver implementations or polyfills.\n */\nexport type ResizeObserverConstructor = new (\n callback: ResizeObserverCallback,\n) => ResizeObserver;\n\ntype DomNodeElement = HTMLElement & {\n __cy_id?: string;\n};\n\ninterface DomNodeData {\n dom?: HTMLElement;\n skipNodeAppend?: boolean;\n skip_node_append?: boolean;\n}\n\n/**\n * Options for {@link DomNodeRenderer}.\n */\nexport interface DomNodeOptions {\n /**\n * Container that receives node DOM elements. When omitted, the extension\n * creates an absolutely positioned overlay next to Cytoscape's canvas.\n */\n domContainer?: HTMLElement;\n\n /**\n * @deprecated Use `domContainer`.\n */\n dom_container?: HTMLElement;\n\n /**\n * ResizeObserver implementation. This is mainly useful for tests or\n * browser environments that provide a polyfill.\n */\n resizeObserver?: ResizeObserverConstructor;\n}\n\ndeclare global {\n namespace cytoscape {\n interface Core {\n /**\n * Enable DOM-backed Cytoscape nodes for this core instance.\n */\n domNode(options?: DomNodeOptions): DomNodeRenderer;\n }\n }\n}\n\ndeclare module \"cytoscape\" {\n namespace cytoscape {\n interface Core {\n /**\n * Enable DOM-backed Cytoscape nodes for this core instance.\n */\n domNode(options?: DomNodeOptions): DomNodeRenderer;\n }\n }\n}\n\n/**\n * Keeps Cytoscape node positions, dimensions, and interaction state mirrored\n * onto caller-supplied DOM elements.\n */\nexport class DomNodeRenderer {\n private readonly cy: cytoscape.Core;\n private readonly nodeElements = new Map<string, DomNodeElement>();\n private readonly resizeObserver: ResizeObserver;\n private readonly container: HTMLElement;\n\n private readonly handleNodeAdd = (event: cytoscape.EventObject): void => {\n this.addNode(event.target as cytoscape.NodeSingular);\n };\n\n private readonly handleNodeRemove = (event: cytoscape.EventObject): void => {\n this.removeNode(event.target as cytoscape.NodeSingular);\n };\n\n private readonly handleNodePosition = (event: cytoscape.EventObject): void => {\n this.syncNodePosition(event.target as cytoscape.NodeSingular);\n };\n\n private readonly handleNodeState = (event: cytoscape.EventObject): void => {\n this.syncNodeState(event.target as cytoscape.NodeSingular);\n };\n\n private readonly handleViewport = (): void => {\n this.syncViewport();\n };\n\n public constructor(cy: cytoscape.Core, options: DomNodeOptions = {}) {\n this.cy = cy;\n this.container = resolveDomContainer(cy, options);\n this.resizeObserver = new (resolveResizeObserver(options))((entries) => {\n for (const entry of entries) {\n this.syncNodeSize(entry.target as DomNodeElement);\n }\n });\n\n this.bindEvents();\n cy.nodes().forEach((node) => {\n this.addNode(node);\n });\n this.syncViewport();\n }\n\n /**\n * Return the DOM element that backs a Cytoscape node id.\n */\n public nodeDom(id: string): HTMLElement | undefined {\n return this.nodeElements.get(id);\n }\n\n /**\n * @deprecated Use {@link nodeDom}.\n */\n public node_dom(id: string): HTMLElement | undefined {\n return this.nodeDom(id);\n }\n\n /**\n * Remove event handlers and disconnect resize observation.\n */\n public destroy(): void {\n this.cy.off(\"add\", \"node\", this.handleNodeAdd);\n this.cy.off(\"remove\", \"node\", this.handleNodeRemove);\n this.cy.off(\"pan zoom\", this.handleViewport);\n this.cy.off(\"position bounds\", \"node\", this.handleNodePosition);\n this.cy.off(\"select unselect grab free\", \"node\", this.handleNodeState);\n this.resizeObserver.disconnect();\n this.nodeElements.clear();\n }\n\n private bindEvents(): void {\n this.cy.on(\"add\", \"node\", this.handleNodeAdd);\n this.cy.on(\"remove\", \"node\", this.handleNodeRemove);\n this.cy.on(\"pan zoom\", this.handleViewport);\n this.cy.on(\"position bounds\", \"node\", this.handleNodePosition);\n this.cy.on(\"select unselect grab free\", \"node\", this.handleNodeState);\n }\n\n private addNode(node: cytoscape.NodeSingular): void {\n const data = node.data() as DomNodeData;\n const element = data.dom as DomNodeElement | undefined;\n\n if (!element) {\n return;\n }\n\n const nodeId = node.id();\n const shouldAppend = data.skipNodeAppend !== true && data.skip_node_append !== true;\n\n if (shouldAppend && element.parentNode !== this.container) {\n this.container.appendChild(element);\n }\n\n element.__cy_id = nodeId;\n this.nodeElements.set(nodeId, element);\n this.resizeObserver.observe(element);\n\n this.syncNodeSize(element);\n this.syncNodePosition(node);\n this.syncNodeState(node);\n }\n\n private removeNode(node: cytoscape.NodeSingular): void {\n const element = this.nodeElements.get(node.id());\n\n if (!element) {\n return;\n }\n\n this.resizeObserver.unobserve(element);\n delete element.__cy_id;\n this.nodeElements.delete(node.id());\n }\n\n private syncViewport(): void {\n const pan = this.cy.pan();\n const zoom = this.cy.zoom();\n const transform = `translate(${String(pan.x)}px, ${String(\n pan.y,\n )}px) scale(${String(zoom)})`;\n\n setMsTransform(this.container, transform);\n this.container.style.transform = transform;\n }\n\n private syncNodeSize(element: DomNodeElement): void {\n if (!element.__cy_id) {\n return;\n }\n\n const node = this.cy.getElementById(element.__cy_id);\n\n if (node.empty()) {\n return;\n }\n\n node.style({\n height: element.offsetHeight,\n shape: \"rectangle\",\n width: element.offsetWidth,\n });\n }\n\n private syncNodePosition(node: cytoscape.NodeSingular): void {\n const element = this.nodeElements.get(node.id());\n\n if (!element) {\n return;\n }\n\n const position = node.position();\n const transform = `translate(-50%, -50%) translate(${position.x.toFixed(\n 2,\n )}px, ${position.y.toFixed(2)}px)`;\n\n element.style.webkitTransform = transform;\n setMsTransform(element, transform);\n element.style.transform = transform;\n element.style.display = \"inline\";\n element.style.position = \"absolute\";\n }\n\n private syncNodeState(node: cytoscape.NodeSingular): void {\n const element = this.nodeElements.get(node.id());\n\n if (!element) {\n return;\n }\n\n const isSelected = node.selected();\n const isActive = isSelected || node.grabbed();\n\n element.classList.toggle(SELECTED_CLASS_NAME, isSelected);\n element.style.zIndex = isActive ? ACTIVE_Z_INDEX : DEFAULT_Z_INDEX;\n }\n}\n\n/**\n * Backwards-compatible class export for consumers that referenced the previous\n * implementation name from bundled output.\n */\nexport { DomNodeRenderer as CytoscapeDomNode };\n\n/**\n * Register the extension with Cytoscape.\n */\nexport default function register(cytoscapeInstance?: CytoscapeRegistry): void {\n if (!cytoscapeInstance) {\n return;\n }\n\n cytoscapeInstance(\n \"core\",\n \"domNode\",\n function domNode(this: cytoscape.Core, options?: DomNodeOptions): DomNodeRenderer {\n return new DomNodeRenderer(this, options);\n },\n );\n}\n\nfunction resolveDomContainer(cy: cytoscape.Core, options: DomNodeOptions): HTMLElement {\n const providedContainer = options.domContainer ?? options.dom_container;\n\n if (providedContainer) {\n return providedContainer;\n }\n\n const cyContainer = cy.container();\n const canvas = cyContainer?.querySelector(\"canvas\");\n\n if (!canvas?.parentNode) {\n throw new Error(\n \"cytoscape-dom-node requires a Cytoscape container with a canvas, or a domContainer option.\",\n );\n }\n\n const container = document.createElement(\"div\");\n container.style.position = \"absolute\";\n container.style.transformOrigin = \"0 0\";\n container.style.zIndex = DEFAULT_Z_INDEX;\n\n canvas.parentNode.appendChild(container);\n\n return container;\n}\n\nfunction resolveResizeObserver(options: DomNodeOptions): ResizeObserverConstructor {\n const ResizeObserverClass = options.resizeObserver ?? globalThis.ResizeObserver;\n\n if (!ResizeObserverClass) {\n throw new Error(\n \"cytoscape-dom-node requires ResizeObserver. Provide a polyfill or pass resizeObserver.\",\n );\n }\n\n return ResizeObserverClass;\n}\n\nfunction setMsTransform(element: HTMLElement, transform: string): void {\n (element.style as CSSStyleDeclaration & { msTransform?: string }).msTransform =\n transform;\n}\n\nconst globalCytoscape = globalThis as typeof globalThis & {\n cytoscape?: CytoscapeRegistry;\n};\n\n/* v8 ignore next 3 */\nif (globalCytoscape.cytoscape) {\n register(globalCytoscape.cytoscape);\n}\n"],"mappings":"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","names":[]}
|
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,204 @@
|
|
|
1
|
+
var __defProp = Object.defineProperty;
|
|
2
|
+
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
3
|
+
var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
4
|
+
|
|
5
|
+
// src/index.ts
|
|
6
|
+
var DEFAULT_Z_INDEX = "10";
|
|
7
|
+
var ACTIVE_Z_INDEX = "11";
|
|
8
|
+
var SELECTED_CLASS_NAME = "selected";
|
|
9
|
+
var DomNodeRenderer = class {
|
|
10
|
+
constructor(cy, options = {}) {
|
|
11
|
+
__publicField(this, "cy");
|
|
12
|
+
__publicField(this, "nodeElements", /* @__PURE__ */ new Map());
|
|
13
|
+
__publicField(this, "resizeObserver");
|
|
14
|
+
__publicField(this, "container");
|
|
15
|
+
__publicField(this, "handleNodeAdd", (event) => {
|
|
16
|
+
this.addNode(event.target);
|
|
17
|
+
});
|
|
18
|
+
__publicField(this, "handleNodeRemove", (event) => {
|
|
19
|
+
this.removeNode(event.target);
|
|
20
|
+
});
|
|
21
|
+
__publicField(this, "handleNodePosition", (event) => {
|
|
22
|
+
this.syncNodePosition(event.target);
|
|
23
|
+
});
|
|
24
|
+
__publicField(this, "handleNodeState", (event) => {
|
|
25
|
+
this.syncNodeState(event.target);
|
|
26
|
+
});
|
|
27
|
+
__publicField(this, "handleViewport", () => {
|
|
28
|
+
this.syncViewport();
|
|
29
|
+
});
|
|
30
|
+
this.cy = cy;
|
|
31
|
+
this.container = resolveDomContainer(cy, options);
|
|
32
|
+
this.resizeObserver = new (resolveResizeObserver(options))((entries) => {
|
|
33
|
+
for (const entry of entries) {
|
|
34
|
+
this.syncNodeSize(entry.target);
|
|
35
|
+
}
|
|
36
|
+
});
|
|
37
|
+
this.bindEvents();
|
|
38
|
+
cy.nodes().forEach((node) => {
|
|
39
|
+
this.addNode(node);
|
|
40
|
+
});
|
|
41
|
+
this.syncViewport();
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Return the DOM element that backs a Cytoscape node id.
|
|
45
|
+
*/
|
|
46
|
+
nodeDom(id) {
|
|
47
|
+
return this.nodeElements.get(id);
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* @deprecated Use {@link nodeDom}.
|
|
51
|
+
*/
|
|
52
|
+
node_dom(id) {
|
|
53
|
+
return this.nodeDom(id);
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Remove event handlers and disconnect resize observation.
|
|
57
|
+
*/
|
|
58
|
+
destroy() {
|
|
59
|
+
this.cy.off("add", "node", this.handleNodeAdd);
|
|
60
|
+
this.cy.off("remove", "node", this.handleNodeRemove);
|
|
61
|
+
this.cy.off("pan zoom", this.handleViewport);
|
|
62
|
+
this.cy.off("position bounds", "node", this.handleNodePosition);
|
|
63
|
+
this.cy.off("select unselect grab free", "node", this.handleNodeState);
|
|
64
|
+
this.resizeObserver.disconnect();
|
|
65
|
+
this.nodeElements.clear();
|
|
66
|
+
}
|
|
67
|
+
bindEvents() {
|
|
68
|
+
this.cy.on("add", "node", this.handleNodeAdd);
|
|
69
|
+
this.cy.on("remove", "node", this.handleNodeRemove);
|
|
70
|
+
this.cy.on("pan zoom", this.handleViewport);
|
|
71
|
+
this.cy.on("position bounds", "node", this.handleNodePosition);
|
|
72
|
+
this.cy.on("select unselect grab free", "node", this.handleNodeState);
|
|
73
|
+
}
|
|
74
|
+
addNode(node) {
|
|
75
|
+
const data = node.data();
|
|
76
|
+
const element = data.dom;
|
|
77
|
+
if (!element) {
|
|
78
|
+
return;
|
|
79
|
+
}
|
|
80
|
+
const nodeId = node.id();
|
|
81
|
+
const shouldAppend = data.skipNodeAppend !== true && data.skip_node_append !== true;
|
|
82
|
+
if (shouldAppend && element.parentNode !== this.container) {
|
|
83
|
+
this.container.appendChild(element);
|
|
84
|
+
}
|
|
85
|
+
element.__cy_id = nodeId;
|
|
86
|
+
this.nodeElements.set(nodeId, element);
|
|
87
|
+
this.resizeObserver.observe(element);
|
|
88
|
+
this.syncNodeSize(element);
|
|
89
|
+
this.syncNodePosition(node);
|
|
90
|
+
this.syncNodeState(node);
|
|
91
|
+
}
|
|
92
|
+
removeNode(node) {
|
|
93
|
+
const element = this.nodeElements.get(node.id());
|
|
94
|
+
if (!element) {
|
|
95
|
+
return;
|
|
96
|
+
}
|
|
97
|
+
this.resizeObserver.unobserve(element);
|
|
98
|
+
delete element.__cy_id;
|
|
99
|
+
this.nodeElements.delete(node.id());
|
|
100
|
+
}
|
|
101
|
+
syncViewport() {
|
|
102
|
+
const pan = this.cy.pan();
|
|
103
|
+
const zoom = this.cy.zoom();
|
|
104
|
+
const transform = `translate(${String(pan.x)}px, ${String(
|
|
105
|
+
pan.y
|
|
106
|
+
)}px) scale(${String(zoom)})`;
|
|
107
|
+
setMsTransform(this.container, transform);
|
|
108
|
+
this.container.style.transform = transform;
|
|
109
|
+
}
|
|
110
|
+
syncNodeSize(element) {
|
|
111
|
+
if (!element.__cy_id) {
|
|
112
|
+
return;
|
|
113
|
+
}
|
|
114
|
+
const node = this.cy.getElementById(element.__cy_id);
|
|
115
|
+
if (node.empty()) {
|
|
116
|
+
return;
|
|
117
|
+
}
|
|
118
|
+
node.style({
|
|
119
|
+
height: element.offsetHeight,
|
|
120
|
+
shape: "rectangle",
|
|
121
|
+
width: element.offsetWidth
|
|
122
|
+
});
|
|
123
|
+
}
|
|
124
|
+
syncNodePosition(node) {
|
|
125
|
+
const element = this.nodeElements.get(node.id());
|
|
126
|
+
if (!element) {
|
|
127
|
+
return;
|
|
128
|
+
}
|
|
129
|
+
const position = node.position();
|
|
130
|
+
const transform = `translate(-50%, -50%) translate(${position.x.toFixed(
|
|
131
|
+
2
|
|
132
|
+
)}px, ${position.y.toFixed(2)}px)`;
|
|
133
|
+
element.style.webkitTransform = transform;
|
|
134
|
+
setMsTransform(element, transform);
|
|
135
|
+
element.style.transform = transform;
|
|
136
|
+
element.style.display = "inline";
|
|
137
|
+
element.style.position = "absolute";
|
|
138
|
+
}
|
|
139
|
+
syncNodeState(node) {
|
|
140
|
+
const element = this.nodeElements.get(node.id());
|
|
141
|
+
if (!element) {
|
|
142
|
+
return;
|
|
143
|
+
}
|
|
144
|
+
const isSelected = node.selected();
|
|
145
|
+
const isActive = isSelected || node.grabbed();
|
|
146
|
+
element.classList.toggle(SELECTED_CLASS_NAME, isSelected);
|
|
147
|
+
element.style.zIndex = isActive ? ACTIVE_Z_INDEX : DEFAULT_Z_INDEX;
|
|
148
|
+
}
|
|
149
|
+
};
|
|
150
|
+
function register(cytoscapeInstance) {
|
|
151
|
+
if (!cytoscapeInstance) {
|
|
152
|
+
return;
|
|
153
|
+
}
|
|
154
|
+
cytoscapeInstance(
|
|
155
|
+
"core",
|
|
156
|
+
"domNode",
|
|
157
|
+
function domNode(options) {
|
|
158
|
+
return new DomNodeRenderer(this, options);
|
|
159
|
+
}
|
|
160
|
+
);
|
|
161
|
+
}
|
|
162
|
+
function resolveDomContainer(cy, options) {
|
|
163
|
+
var _a;
|
|
164
|
+
const providedContainer = (_a = options.domContainer) != null ? _a : options.dom_container;
|
|
165
|
+
if (providedContainer) {
|
|
166
|
+
return providedContainer;
|
|
167
|
+
}
|
|
168
|
+
const cyContainer = cy.container();
|
|
169
|
+
const canvas = cyContainer == null ? void 0 : cyContainer.querySelector("canvas");
|
|
170
|
+
if (!(canvas == null ? void 0 : canvas.parentNode)) {
|
|
171
|
+
throw new Error(
|
|
172
|
+
"cytoscape-dom-node requires a Cytoscape container with a canvas, or a domContainer option."
|
|
173
|
+
);
|
|
174
|
+
}
|
|
175
|
+
const container = document.createElement("div");
|
|
176
|
+
container.style.position = "absolute";
|
|
177
|
+
container.style.transformOrigin = "0 0";
|
|
178
|
+
container.style.zIndex = DEFAULT_Z_INDEX;
|
|
179
|
+
canvas.parentNode.appendChild(container);
|
|
180
|
+
return container;
|
|
181
|
+
}
|
|
182
|
+
function resolveResizeObserver(options) {
|
|
183
|
+
var _a;
|
|
184
|
+
const ResizeObserverClass = (_a = options.resizeObserver) != null ? _a : globalThis.ResizeObserver;
|
|
185
|
+
if (!ResizeObserverClass) {
|
|
186
|
+
throw new Error(
|
|
187
|
+
"cytoscape-dom-node requires ResizeObserver. Provide a polyfill or pass resizeObserver."
|
|
188
|
+
);
|
|
189
|
+
}
|
|
190
|
+
return ResizeObserverClass;
|
|
191
|
+
}
|
|
192
|
+
function setMsTransform(element, transform) {
|
|
193
|
+
element.style.msTransform = transform;
|
|
194
|
+
}
|
|
195
|
+
var globalCytoscape = globalThis;
|
|
196
|
+
if (globalCytoscape.cytoscape) {
|
|
197
|
+
register(globalCytoscape.cytoscape);
|
|
198
|
+
}
|
|
199
|
+
export {
|
|
200
|
+
DomNodeRenderer as CytoscapeDomNode,
|
|
201
|
+
DomNodeRenderer,
|
|
202
|
+
register as default
|
|
203
|
+
};
|
|
204
|
+
//# sourceMappingURL=index.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/index.ts"],"sourcesContent":["/**\n * Index.\n *\n * @packageDocumentation\n */\n\nimport type cytoscape from \"cytoscape\";\n\nconst DEFAULT_Z_INDEX = \"10\";\nconst ACTIVE_Z_INDEX = \"11\";\nconst SELECTED_CLASS_NAME = \"selected\";\n\ntype CytoscapeRegistry = typeof cytoscape;\n\n/**\n * Constructor shape for ResizeObserver implementations or polyfills.\n */\nexport type ResizeObserverConstructor = new (\n callback: ResizeObserverCallback,\n) => ResizeObserver;\n\ntype DomNodeElement = HTMLElement & {\n __cy_id?: string;\n};\n\ninterface DomNodeData {\n dom?: HTMLElement;\n skipNodeAppend?: boolean;\n skip_node_append?: boolean;\n}\n\n/**\n * Options for {@link DomNodeRenderer}.\n */\nexport interface DomNodeOptions {\n /**\n * Container that receives node DOM elements. When omitted, the extension\n * creates an absolutely positioned overlay next to Cytoscape's canvas.\n */\n domContainer?: HTMLElement;\n\n /**\n * @deprecated Use `domContainer`.\n */\n dom_container?: HTMLElement;\n\n /**\n * ResizeObserver implementation. This is mainly useful for tests or\n * browser environments that provide a polyfill.\n */\n resizeObserver?: ResizeObserverConstructor;\n}\n\ndeclare global {\n namespace cytoscape {\n interface Core {\n /**\n * Enable DOM-backed Cytoscape nodes for this core instance.\n */\n domNode(options?: DomNodeOptions): DomNodeRenderer;\n }\n }\n}\n\ndeclare module \"cytoscape\" {\n namespace cytoscape {\n interface Core {\n /**\n * Enable DOM-backed Cytoscape nodes for this core instance.\n */\n domNode(options?: DomNodeOptions): DomNodeRenderer;\n }\n }\n}\n\n/**\n * Keeps Cytoscape node positions, dimensions, and interaction state mirrored\n * onto caller-supplied DOM elements.\n */\nexport class DomNodeRenderer {\n private readonly cy: cytoscape.Core;\n private readonly nodeElements = new Map<string, DomNodeElement>();\n private readonly resizeObserver: ResizeObserver;\n private readonly container: HTMLElement;\n\n private readonly handleNodeAdd = (event: cytoscape.EventObject): void => {\n this.addNode(event.target as cytoscape.NodeSingular);\n };\n\n private readonly handleNodeRemove = (event: cytoscape.EventObject): void => {\n this.removeNode(event.target as cytoscape.NodeSingular);\n };\n\n private readonly handleNodePosition = (event: cytoscape.EventObject): void => {\n this.syncNodePosition(event.target as cytoscape.NodeSingular);\n };\n\n private readonly handleNodeState = (event: cytoscape.EventObject): void => {\n this.syncNodeState(event.target as cytoscape.NodeSingular);\n };\n\n private readonly handleViewport = (): void => {\n this.syncViewport();\n };\n\n public constructor(cy: cytoscape.Core, options: DomNodeOptions = {}) {\n this.cy = cy;\n this.container = resolveDomContainer(cy, options);\n this.resizeObserver = new (resolveResizeObserver(options))((entries) => {\n for (const entry of entries) {\n this.syncNodeSize(entry.target as DomNodeElement);\n }\n });\n\n this.bindEvents();\n cy.nodes().forEach((node) => {\n this.addNode(node);\n });\n this.syncViewport();\n }\n\n /**\n * Return the DOM element that backs a Cytoscape node id.\n */\n public nodeDom(id: string): HTMLElement | undefined {\n return this.nodeElements.get(id);\n }\n\n /**\n * @deprecated Use {@link nodeDom}.\n */\n public node_dom(id: string): HTMLElement | undefined {\n return this.nodeDom(id);\n }\n\n /**\n * Remove event handlers and disconnect resize observation.\n */\n public destroy(): void {\n this.cy.off(\"add\", \"node\", this.handleNodeAdd);\n this.cy.off(\"remove\", \"node\", this.handleNodeRemove);\n this.cy.off(\"pan zoom\", this.handleViewport);\n this.cy.off(\"position bounds\", \"node\", this.handleNodePosition);\n this.cy.off(\"select unselect grab free\", \"node\", this.handleNodeState);\n this.resizeObserver.disconnect();\n this.nodeElements.clear();\n }\n\n private bindEvents(): void {\n this.cy.on(\"add\", \"node\", this.handleNodeAdd);\n this.cy.on(\"remove\", \"node\", this.handleNodeRemove);\n this.cy.on(\"pan zoom\", this.handleViewport);\n this.cy.on(\"position bounds\", \"node\", this.handleNodePosition);\n this.cy.on(\"select unselect grab free\", \"node\", this.handleNodeState);\n }\n\n private addNode(node: cytoscape.NodeSingular): void {\n const data = node.data() as DomNodeData;\n const element = data.dom as DomNodeElement | undefined;\n\n if (!element) {\n return;\n }\n\n const nodeId = node.id();\n const shouldAppend = data.skipNodeAppend !== true && data.skip_node_append !== true;\n\n if (shouldAppend && element.parentNode !== this.container) {\n this.container.appendChild(element);\n }\n\n element.__cy_id = nodeId;\n this.nodeElements.set(nodeId, element);\n this.resizeObserver.observe(element);\n\n this.syncNodeSize(element);\n this.syncNodePosition(node);\n this.syncNodeState(node);\n }\n\n private removeNode(node: cytoscape.NodeSingular): void {\n const element = this.nodeElements.get(node.id());\n\n if (!element) {\n return;\n }\n\n this.resizeObserver.unobserve(element);\n delete element.__cy_id;\n this.nodeElements.delete(node.id());\n }\n\n private syncViewport(): void {\n const pan = this.cy.pan();\n const zoom = this.cy.zoom();\n const transform = `translate(${String(pan.x)}px, ${String(\n pan.y,\n )}px) scale(${String(zoom)})`;\n\n setMsTransform(this.container, transform);\n this.container.style.transform = transform;\n }\n\n private syncNodeSize(element: DomNodeElement): void {\n if (!element.__cy_id) {\n return;\n }\n\n const node = this.cy.getElementById(element.__cy_id);\n\n if (node.empty()) {\n return;\n }\n\n node.style({\n height: element.offsetHeight,\n shape: \"rectangle\",\n width: element.offsetWidth,\n });\n }\n\n private syncNodePosition(node: cytoscape.NodeSingular): void {\n const element = this.nodeElements.get(node.id());\n\n if (!element) {\n return;\n }\n\n const position = node.position();\n const transform = `translate(-50%, -50%) translate(${position.x.toFixed(\n 2,\n )}px, ${position.y.toFixed(2)}px)`;\n\n element.style.webkitTransform = transform;\n setMsTransform(element, transform);\n element.style.transform = transform;\n element.style.display = \"inline\";\n element.style.position = \"absolute\";\n }\n\n private syncNodeState(node: cytoscape.NodeSingular): void {\n const element = this.nodeElements.get(node.id());\n\n if (!element) {\n return;\n }\n\n const isSelected = node.selected();\n const isActive = isSelected || node.grabbed();\n\n element.classList.toggle(SELECTED_CLASS_NAME, isSelected);\n element.style.zIndex = isActive ? ACTIVE_Z_INDEX : DEFAULT_Z_INDEX;\n }\n}\n\n/**\n * Backwards-compatible class export for consumers that referenced the previous\n * implementation name from bundled output.\n */\nexport { DomNodeRenderer as CytoscapeDomNode };\n\n/**\n * Register the extension with Cytoscape.\n */\nexport default function register(cytoscapeInstance?: CytoscapeRegistry): void {\n if (!cytoscapeInstance) {\n return;\n }\n\n cytoscapeInstance(\n \"core\",\n \"domNode\",\n function domNode(this: cytoscape.Core, options?: DomNodeOptions): DomNodeRenderer {\n return new DomNodeRenderer(this, options);\n },\n );\n}\n\nfunction resolveDomContainer(cy: cytoscape.Core, options: DomNodeOptions): HTMLElement {\n const providedContainer = options.domContainer ?? options.dom_container;\n\n if (providedContainer) {\n return providedContainer;\n }\n\n const cyContainer = cy.container();\n const canvas = cyContainer?.querySelector(\"canvas\");\n\n if (!canvas?.parentNode) {\n throw new Error(\n \"cytoscape-dom-node requires a Cytoscape container with a canvas, or a domContainer option.\",\n );\n }\n\n const container = document.createElement(\"div\");\n container.style.position = \"absolute\";\n container.style.transformOrigin = \"0 0\";\n container.style.zIndex = DEFAULT_Z_INDEX;\n\n canvas.parentNode.appendChild(container);\n\n return container;\n}\n\nfunction resolveResizeObserver(options: DomNodeOptions): ResizeObserverConstructor {\n const ResizeObserverClass = options.resizeObserver ?? globalThis.ResizeObserver;\n\n if (!ResizeObserverClass) {\n throw new Error(\n \"cytoscape-dom-node requires ResizeObserver. Provide a polyfill or pass resizeObserver.\",\n );\n }\n\n return ResizeObserverClass;\n}\n\nfunction setMsTransform(element: HTMLElement, transform: string): void {\n (element.style as CSSStyleDeclaration & { msTransform?: string }).msTransform =\n transform;\n}\n\nconst globalCytoscape = globalThis as typeof globalThis & {\n cytoscape?: CytoscapeRegistry;\n};\n\n/* v8 ignore next 3 */\nif (globalCytoscape.cytoscape) {\n register(globalCytoscape.cytoscape);\n}\n"],"mappings":"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","names":[]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "cytoscape-dom-node",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "2.0.1",
|
|
4
4
|
"description": "Cytoscape extension for making nodes into DOM elements",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"cytoscape",
|
|
@@ -13,10 +13,40 @@
|
|
|
13
13
|
"email": "mjw@methodanalysis.com"
|
|
14
14
|
},
|
|
15
15
|
"license": "MIT",
|
|
16
|
-
"main": "
|
|
16
|
+
"main": "./dist/index.cjs",
|
|
17
|
+
"module": "./dist/index.mjs",
|
|
18
|
+
"types": "./dist/index.d.ts",
|
|
19
|
+
"browser": "./dist/index.global.js",
|
|
20
|
+
"unpkg": "./dist/index.global.js",
|
|
21
|
+
"jsdelivr": "./dist/index.global.js",
|
|
22
|
+
"exports": {
|
|
23
|
+
".": {
|
|
24
|
+
"types": "./dist/index.d.ts",
|
|
25
|
+
"import": "./dist/index.mjs",
|
|
26
|
+
"require": "./dist/index.cjs"
|
|
27
|
+
},
|
|
28
|
+
"./src/index.js": "./src/index.js",
|
|
29
|
+
"./package.json": "./package.json"
|
|
30
|
+
},
|
|
31
|
+
"files": [
|
|
32
|
+
"dist",
|
|
33
|
+
"src/index.js",
|
|
34
|
+
"LICENSE",
|
|
35
|
+
"README.md"
|
|
36
|
+
],
|
|
17
37
|
"url": "https://github.com/mwri/cytoscape-dom-node",
|
|
18
38
|
"scripts": {
|
|
19
|
-
"
|
|
39
|
+
"build": "tsup",
|
|
40
|
+
"build:demo:modern": "tsc -p demos/modern/tsconfig.json",
|
|
41
|
+
"check": "npm run lint && npm run typecheck && npm run test:coverage && npm run build && npm run build:demo:modern && npm run docs",
|
|
42
|
+
"docs": "typedoc",
|
|
43
|
+
"format": "prettier --write .",
|
|
44
|
+
"format:check": "prettier --check .",
|
|
45
|
+
"lint": "eslint .",
|
|
46
|
+
"prepublishOnly": "npm run check",
|
|
47
|
+
"test": "vitest run",
|
|
48
|
+
"test:coverage": "vitest run --coverage",
|
|
49
|
+
"typecheck": "tsc --noEmit"
|
|
20
50
|
},
|
|
21
51
|
"repository": {
|
|
22
52
|
"type": "git",
|
|
@@ -30,9 +60,17 @@
|
|
|
30
60
|
"cytoscape": "^3.19.0"
|
|
31
61
|
},
|
|
32
62
|
"devDependencies": {
|
|
33
|
-
"
|
|
34
|
-
"
|
|
35
|
-
"
|
|
36
|
-
"
|
|
63
|
+
"@eslint/js": "^10.0.1",
|
|
64
|
+
"@types/node": "^25.6.2",
|
|
65
|
+
"@vitest/coverage-v8": "^4.1.5",
|
|
66
|
+
"cytoscape": "^3.33.3",
|
|
67
|
+
"eslint": "^10.3.0",
|
|
68
|
+
"jsdom": "^29.1.1",
|
|
69
|
+
"prettier": "^3.8.3",
|
|
70
|
+
"tsup": "^8.5.1",
|
|
71
|
+
"typedoc": "^0.28.19",
|
|
72
|
+
"typescript": "^6.0.3",
|
|
73
|
+
"typescript-eslint": "^8.59.2",
|
|
74
|
+
"vitest": "^4.1.5"
|
|
37
75
|
}
|
|
38
76
|
}
|