Files
datascape/assets/canvas/select.js
T
2026-09-17 17:07:04 +02:00

78 lines
2.5 KiB
JavaScript

// select.js — which nodes and edges are selected.
//
// Kept apart from the document so selection never lands in the undo stack or
// on disk: undoing an edit should restore geometry, not re-select whatever
// happened to be highlighted at the time.
window.Canvas = window.Canvas || {};
Canvas.Select = (function () {
var nodes = {};
var edges = {};
var listeners = [];
function emit() {
for (var i = 0; i < listeners.length; i++) listeners[i]();
}
function keys(obj) { return Object.keys(obj); }
return {
nodes: function () { return keys(nodes); },
edges: function () { return keys(edges); },
hasNode: function (id) { return !!nodes[id]; },
hasEdge: function (id) { return !!edges[id]; },
isEmpty: function () { return !keys(nodes).length && !keys(edges).length; },
count: function () { return keys(nodes).length + keys(edges).length; },
set: function (nodeIds, edgeIds) {
nodes = {};
edges = {};
(nodeIds || []).forEach(function (id) { nodes[id] = true; });
(edgeIds || []).forEach(function (id) { edges[id] = true; });
emit();
},
addNode: function (id) {
if (nodes[id]) return;
nodes[id] = true;
emit();
},
toggleNode: function (id) {
if (nodes[id]) delete nodes[id]; else nodes[id] = true;
emit();
},
toggleEdge: function (id) {
if (edges[id]) delete edges[id]; else edges[id] = true;
emit();
},
clear: function () {
if (!keys(nodes).length && !keys(edges).length) return;
nodes = {};
edges = {};
emit();
},
// prune drops ids that no longer exist. Called after undo/redo, where
// the document can lose nodes the selection still refers to.
prune: function (doc) {
var changed = false;
var live = {};
doc.nodes.forEach(function (n) { live[n.id] = true; });
keys(nodes).forEach(function (id) {
if (!live[id]) { delete nodes[id]; changed = true; }
});
var liveEdges = {};
doc.edges.forEach(function (e) { liveEdges[e.id] = true; });
keys(edges).forEach(function (id) {
if (!liveEdges[id]) { delete edges[id]; changed = true; }
});
if (changed) emit();
},
onChange: function (fn) { listeners.push(fn); }
};
})();