"use client";
import { n as __commonJSMin, r as __toESM, t as require_react } from "./react-Ea1HnpA1.js";
import { t as require_react_dom } from "./react-dom.js";
import { t as require_jsx_runtime } from "./react_jsx-runtime.js";
//#region node_modules/classcat/index.js
var import_react = /* @__PURE__ */ __toESM(require_react(), 1);
var import_jsx_runtime = require_jsx_runtime();
function cc(names) {
if (typeof names === "string" || typeof names === "number") return "" + names;
let out = "";
if (Array.isArray(names)) {
for (let i = 0, tmp; i < names.length; i++) if ((tmp = cc(names[i])) !== "") out += (out && " ") + tmp;
} else for (let k in names) if (names[k]) out += (out && " ") + k;
return out;
}
//#endregion
//#region node_modules/d3-dispatch/src/dispatch.js
var noop = { value: () => {} };
function dispatch() {
for (var i = 0, n = arguments.length, _ = {}, t; i < n; ++i) {
if (!(t = arguments[i] + "") || t in _ || /[\s.]/.test(t)) throw new Error("illegal type: " + t);
_[t] = [];
}
return new Dispatch(_);
}
function Dispatch(_) {
this._ = _;
}
function parseTypenames$1(typenames, types) {
return typenames.trim().split(/^|\s+/).map(function(t) {
var name = "", i = t.indexOf(".");
if (i >= 0) name = t.slice(i + 1), t = t.slice(0, i);
if (t && !types.hasOwnProperty(t)) throw new Error("unknown type: " + t);
return {
type: t,
name
};
});
}
Dispatch.prototype = dispatch.prototype = {
constructor: Dispatch,
on: function(typename, callback) {
var _ = this._, T = parseTypenames$1(typename + "", _), t, i = -1, n = T.length;
if (arguments.length < 2) {
while (++i < n) if ((t = (typename = T[i]).type) && (t = get$1(_[t], typename.name))) return t;
return;
}
if (callback != null && typeof callback !== "function") throw new Error("invalid callback: " + callback);
while (++i < n) if (t = (typename = T[i]).type) _[t] = set$1(_[t], typename.name, callback);
else if (callback == null) for (t in _) _[t] = set$1(_[t], typename.name, null);
return this;
},
copy: function() {
var copy = {}, _ = this._;
for (var t in _) copy[t] = _[t].slice();
return new Dispatch(copy);
},
call: function(type, that) {
if ((n = arguments.length - 2) > 0) for (var args = new Array(n), i = 0, n, t; i < n; ++i) args[i] = arguments[i + 2];
if (!this._.hasOwnProperty(type)) throw new Error("unknown type: " + type);
for (t = this._[type], i = 0, n = t.length; i < n; ++i) t[i].value.apply(that, args);
},
apply: function(type, that, args) {
if (!this._.hasOwnProperty(type)) throw new Error("unknown type: " + type);
for (var t = this._[type], i = 0, n = t.length; i < n; ++i) t[i].value.apply(that, args);
}
};
function get$1(type, name) {
for (var i = 0, n = type.length, c; i < n; ++i) if ((c = type[i]).name === name) return c.value;
}
function set$1(type, name, callback) {
for (var i = 0, n = type.length; i < n; ++i) if (type[i].name === name) {
type[i] = noop, type = type.slice(0, i).concat(type.slice(i + 1));
break;
}
if (callback != null) type.push({
name,
value: callback
});
return type;
}
var namespaces_default = {
svg: "http://www.w3.org/2000/svg",
xhtml: "http://www.w3.org/1999/xhtml",
xlink: "http://www.w3.org/1999/xlink",
xml: "http://www.w3.org/XML/1998/namespace",
xmlns: "http://www.w3.org/2000/xmlns/"
};
//#endregion
//#region node_modules/d3-selection/src/namespace.js
function namespace_default(name) {
var prefix = name += "", i = prefix.indexOf(":");
if (i >= 0 && (prefix = name.slice(0, i)) !== "xmlns") name = name.slice(i + 1);
return namespaces_default.hasOwnProperty(prefix) ? {
space: namespaces_default[prefix],
local: name
} : name;
}
//#endregion
//#region node_modules/d3-selection/src/creator.js
function creatorInherit(name) {
return function() {
var document = this.ownerDocument, uri = this.namespaceURI;
return uri === "http://www.w3.org/1999/xhtml" && document.documentElement.namespaceURI === "http://www.w3.org/1999/xhtml" ? document.createElement(name) : document.createElementNS(uri, name);
};
}
function creatorFixed(fullname) {
return function() {
return this.ownerDocument.createElementNS(fullname.space, fullname.local);
};
}
function creator_default(name) {
var fullname = namespace_default(name);
return (fullname.local ? creatorFixed : creatorInherit)(fullname);
}
//#endregion
//#region node_modules/d3-selection/src/selector.js
function none() {}
function selector_default(selector) {
return selector == null ? none : function() {
return this.querySelector(selector);
};
}
//#endregion
//#region node_modules/d3-selection/src/selection/select.js
function select_default$2(select) {
if (typeof select !== "function") select = selector_default(select);
for (var groups = this._groups, m = groups.length, subgroups = new Array(m), j = 0; j < m; ++j) for (var group = groups[j], n = group.length, subgroup = subgroups[j] = new Array(n), node, subnode, i = 0; i < n; ++i) if ((node = group[i]) && (subnode = select.call(node, node.__data__, i, group))) {
if ("__data__" in node) subnode.__data__ = node.__data__;
subgroup[i] = subnode;
}
return new Selection$1(subgroups, this._parents);
}
//#endregion
//#region node_modules/d3-selection/src/array.js
function array(x) {
return x == null ? [] : Array.isArray(x) ? x : Array.from(x);
}
//#endregion
//#region node_modules/d3-selection/src/selectorAll.js
function empty() {
return [];
}
function selectorAll_default(selector) {
return selector == null ? empty : function() {
return this.querySelectorAll(selector);
};
}
//#endregion
//#region node_modules/d3-selection/src/selection/selectAll.js
function arrayAll(select) {
return function() {
return array(select.apply(this, arguments));
};
}
function selectAll_default$1(select) {
if (typeof select === "function") select = arrayAll(select);
else select = selectorAll_default(select);
for (var groups = this._groups, m = groups.length, subgroups = [], parents = [], j = 0; j < m; ++j) for (var group = groups[j], n = group.length, node, i = 0; i < n; ++i) if (node = group[i]) {
subgroups.push(select.call(node, node.__data__, i, group));
parents.push(node);
}
return new Selection$1(subgroups, parents);
}
//#endregion
//#region node_modules/d3-selection/src/matcher.js
function matcher_default(selector) {
return function() {
return this.matches(selector);
};
}
function childMatcher(selector) {
return function(node) {
return node.matches(selector);
};
}
//#endregion
//#region node_modules/d3-selection/src/selection/selectChild.js
var find = Array.prototype.find;
function childFind(match) {
return function() {
return find.call(this.children, match);
};
}
function childFirst() {
return this.firstElementChild;
}
function selectChild_default(match) {
return this.select(match == null ? childFirst : childFind(typeof match === "function" ? match : childMatcher(match)));
}
//#endregion
//#region node_modules/d3-selection/src/selection/selectChildren.js
var filter = Array.prototype.filter;
function children() {
return Array.from(this.children);
}
function childrenFilter(match) {
return function() {
return filter.call(this.children, match);
};
}
function selectChildren_default(match) {
return this.selectAll(match == null ? children : childrenFilter(typeof match === "function" ? match : childMatcher(match)));
}
//#endregion
//#region node_modules/d3-selection/src/selection/filter.js
function filter_default$1(match) {
if (typeof match !== "function") match = matcher_default(match);
for (var groups = this._groups, m = groups.length, subgroups = new Array(m), j = 0; j < m; ++j) for (var group = groups[j], n = group.length, subgroup = subgroups[j] = [], node, i = 0; i < n; ++i) if ((node = group[i]) && match.call(node, node.__data__, i, group)) subgroup.push(node);
return new Selection$1(subgroups, this._parents);
}
//#endregion
//#region node_modules/d3-selection/src/selection/sparse.js
function sparse_default(update) {
return new Array(update.length);
}
//#endregion
//#region node_modules/d3-selection/src/selection/enter.js
function enter_default() {
return new Selection$1(this._enter || this._groups.map(sparse_default), this._parents);
}
function EnterNode(parent, datum) {
this.ownerDocument = parent.ownerDocument;
this.namespaceURI = parent.namespaceURI;
this._next = null;
this._parent = parent;
this.__data__ = datum;
}
EnterNode.prototype = {
constructor: EnterNode,
appendChild: function(child) {
return this._parent.insertBefore(child, this._next);
},
insertBefore: function(child, next) {
return this._parent.insertBefore(child, next);
},
querySelector: function(selector) {
return this._parent.querySelector(selector);
},
querySelectorAll: function(selector) {
return this._parent.querySelectorAll(selector);
}
};
//#endregion
//#region node_modules/d3-selection/src/constant.js
function constant_default$3(x) {
return function() {
return x;
};
}
//#endregion
//#region node_modules/d3-selection/src/selection/data.js
function bindIndex(parent, group, enter, update, exit, data) {
var i = 0, node, groupLength = group.length, dataLength = data.length;
for (; i < dataLength; ++i) if (node = group[i]) {
node.__data__ = data[i];
update[i] = node;
} else enter[i] = new EnterNode(parent, data[i]);
for (; i < groupLength; ++i) if (node = group[i]) exit[i] = node;
}
function bindKey(parent, group, enter, update, exit, data, key) {
var i, node, nodeByKeyValue = /* @__PURE__ */ new Map(), groupLength = group.length, dataLength = data.length, keyValues = new Array(groupLength), keyValue;
for (i = 0; i < groupLength; ++i) if (node = group[i]) {
keyValues[i] = keyValue = key.call(node, node.__data__, i, group) + "";
if (nodeByKeyValue.has(keyValue)) exit[i] = node;
else nodeByKeyValue.set(keyValue, node);
}
for (i = 0; i < dataLength; ++i) {
keyValue = key.call(parent, data[i], i, data) + "";
if (node = nodeByKeyValue.get(keyValue)) {
update[i] = node;
node.__data__ = data[i];
nodeByKeyValue.delete(keyValue);
} else enter[i] = new EnterNode(parent, data[i]);
}
for (i = 0; i < groupLength; ++i) if ((node = group[i]) && nodeByKeyValue.get(keyValues[i]) === node) exit[i] = node;
}
function datum(node) {
return node.__data__;
}
function data_default(value, key) {
if (!arguments.length) return Array.from(this, datum);
var bind = key ? bindKey : bindIndex, parents = this._parents, groups = this._groups;
if (typeof value !== "function") value = constant_default$3(value);
for (var m = groups.length, update = new Array(m), enter = new Array(m), exit = new Array(m), j = 0; j < m; ++j) {
var parent = parents[j], group = groups[j], groupLength = group.length, data = arraylike(value.call(parent, parent && parent.__data__, j, parents)), dataLength = data.length, enterGroup = enter[j] = new Array(dataLength), updateGroup = update[j] = new Array(dataLength);
bind(parent, group, enterGroup, updateGroup, exit[j] = new Array(groupLength), data, key);
for (var i0 = 0, i1 = 0, previous, next; i0 < dataLength; ++i0) if (previous = enterGroup[i0]) {
if (i0 >= i1) i1 = i0 + 1;
while (!(next = updateGroup[i1]) && ++i1 < dataLength);
previous._next = next || null;
}
}
update = new Selection$1(update, parents);
update._enter = enter;
update._exit = exit;
return update;
}
function arraylike(data) {
return typeof data === "object" && "length" in data ? data : Array.from(data);
}
//#endregion
//#region node_modules/d3-selection/src/selection/exit.js
function exit_default() {
return new Selection$1(this._exit || this._groups.map(sparse_default), this._parents);
}
//#endregion
//#region node_modules/d3-selection/src/selection/join.js
function join_default(onenter, onupdate, onexit) {
var enter = this.enter(), update = this, exit = this.exit();
if (typeof onenter === "function") {
enter = onenter(enter);
if (enter) enter = enter.selection();
} else enter = enter.append(onenter + "");
if (onupdate != null) {
update = onupdate(update);
if (update) update = update.selection();
}
if (onexit == null) exit.remove();
else onexit(exit);
return enter && update ? enter.merge(update).order() : update;
}
//#endregion
//#region node_modules/d3-selection/src/selection/merge.js
function merge_default$1(context) {
var selection = context.selection ? context.selection() : context;
for (var groups0 = this._groups, groups1 = selection._groups, m0 = groups0.length, m1 = groups1.length, m = Math.min(m0, m1), merges = new Array(m0), j = 0; j < m; ++j) for (var group0 = groups0[j], group1 = groups1[j], n = group0.length, merge = merges[j] = new Array(n), node, i = 0; i < n; ++i) if (node = group0[i] || group1[i]) merge[i] = node;
for (; j < m0; ++j) merges[j] = groups0[j];
return new Selection$1(merges, this._parents);
}
//#endregion
//#region node_modules/d3-selection/src/selection/order.js
function order_default() {
for (var groups = this._groups, j = -1, m = groups.length; ++j < m;) for (var group = groups[j], i = group.length - 1, next = group[i], node; --i >= 0;) if (node = group[i]) {
if (next && node.compareDocumentPosition(next) ^ 4) next.parentNode.insertBefore(node, next);
next = node;
}
return this;
}
//#endregion
//#region node_modules/d3-selection/src/selection/sort.js
function sort_default(compare) {
if (!compare) compare = ascending;
function compareNode(a, b) {
return a && b ? compare(a.__data__, b.__data__) : !a - !b;
}
for (var groups = this._groups, m = groups.length, sortgroups = new Array(m), j = 0; j < m; ++j) {
for (var group = groups[j], n = group.length, sortgroup = sortgroups[j] = new Array(n), node, i = 0; i < n; ++i) if (node = group[i]) sortgroup[i] = node;
sortgroup.sort(compareNode);
}
return new Selection$1(sortgroups, this._parents).order();
}
function ascending(a, b) {
return a < b ? -1 : a > b ? 1 : a >= b ? 0 : NaN;
}
//#endregion
//#region node_modules/d3-selection/src/selection/call.js
function call_default() {
var callback = arguments[0];
arguments[0] = this;
callback.apply(null, arguments);
return this;
}
//#endregion
//#region node_modules/d3-selection/src/selection/nodes.js
function nodes_default() {
return Array.from(this);
}
//#endregion
//#region node_modules/d3-selection/src/selection/node.js
function node_default() {
for (var groups = this._groups, j = 0, m = groups.length; j < m; ++j) for (var group = groups[j], i = 0, n = group.length; i < n; ++i) {
var node = group[i];
if (node) return node;
}
return null;
}
//#endregion
//#region node_modules/d3-selection/src/selection/size.js
function size_default() {
let size = 0;
for (const node of this) ++size;
return size;
}
//#endregion
//#region node_modules/d3-selection/src/selection/empty.js
function empty_default() {
return !this.node();
}
//#endregion
//#region node_modules/d3-selection/src/selection/each.js
function each_default(callback) {
for (var groups = this._groups, j = 0, m = groups.length; j < m; ++j) for (var group = groups[j], i = 0, n = group.length, node; i < n; ++i) if (node = group[i]) callback.call(node, node.__data__, i, group);
return this;
}
//#endregion
//#region node_modules/d3-selection/src/selection/attr.js
function attrRemove$1(name) {
return function() {
this.removeAttribute(name);
};
}
function attrRemoveNS$1(fullname) {
return function() {
this.removeAttributeNS(fullname.space, fullname.local);
};
}
function attrConstant$1(name, value) {
return function() {
this.setAttribute(name, value);
};
}
function attrConstantNS$1(fullname, value) {
return function() {
this.setAttributeNS(fullname.space, fullname.local, value);
};
}
function attrFunction$1(name, value) {
return function() {
var v = value.apply(this, arguments);
if (v == null) this.removeAttribute(name);
else this.setAttribute(name, v);
};
}
function attrFunctionNS$1(fullname, value) {
return function() {
var v = value.apply(this, arguments);
if (v == null) this.removeAttributeNS(fullname.space, fullname.local);
else this.setAttributeNS(fullname.space, fullname.local, v);
};
}
function attr_default$1(name, value) {
var fullname = namespace_default(name);
if (arguments.length < 2) {
var node = this.node();
return fullname.local ? node.getAttributeNS(fullname.space, fullname.local) : node.getAttribute(fullname);
}
return this.each((value == null ? fullname.local ? attrRemoveNS$1 : attrRemove$1 : typeof value === "function" ? fullname.local ? attrFunctionNS$1 : attrFunction$1 : fullname.local ? attrConstantNS$1 : attrConstant$1)(fullname, value));
}
//#endregion
//#region node_modules/d3-selection/src/window.js
function window_default(node) {
return node.ownerDocument && node.ownerDocument.defaultView || node.document && node || node.defaultView;
}
//#endregion
//#region node_modules/d3-selection/src/selection/style.js
function styleRemove$1(name) {
return function() {
this.style.removeProperty(name);
};
}
function styleConstant$1(name, value, priority) {
return function() {
this.style.setProperty(name, value, priority);
};
}
function styleFunction$1(name, value, priority) {
return function() {
var v = value.apply(this, arguments);
if (v == null) this.style.removeProperty(name);
else this.style.setProperty(name, v, priority);
};
}
function style_default$1(name, value, priority) {
return arguments.length > 1 ? this.each((value == null ? styleRemove$1 : typeof value === "function" ? styleFunction$1 : styleConstant$1)(name, value, priority == null ? "" : priority)) : styleValue(this.node(), name);
}
function styleValue(node, name) {
return node.style.getPropertyValue(name) || window_default(node).getComputedStyle(node, null).getPropertyValue(name);
}
//#endregion
//#region node_modules/d3-selection/src/selection/property.js
function propertyRemove(name) {
return function() {
delete this[name];
};
}
function propertyConstant(name, value) {
return function() {
this[name] = value;
};
}
function propertyFunction(name, value) {
return function() {
var v = value.apply(this, arguments);
if (v == null) delete this[name];
else this[name] = v;
};
}
function property_default(name, value) {
return arguments.length > 1 ? this.each((value == null ? propertyRemove : typeof value === "function" ? propertyFunction : propertyConstant)(name, value)) : this.node()[name];
}
//#endregion
//#region node_modules/d3-selection/src/selection/classed.js
function classArray(string) {
return string.trim().split(/^|\s+/);
}
function classList(node) {
return node.classList || new ClassList(node);
}
function ClassList(node) {
this._node = node;
this._names = classArray(node.getAttribute("class") || "");
}
ClassList.prototype = {
add: function(name) {
if (this._names.indexOf(name) < 0) {
this._names.push(name);
this._node.setAttribute("class", this._names.join(" "));
}
},
remove: function(name) {
var i = this._names.indexOf(name);
if (i >= 0) {
this._names.splice(i, 1);
this._node.setAttribute("class", this._names.join(" "));
}
},
contains: function(name) {
return this._names.indexOf(name) >= 0;
}
};
function classedAdd(node, names) {
var list = classList(node), i = -1, n = names.length;
while (++i < n) list.add(names[i]);
}
function classedRemove(node, names) {
var list = classList(node), i = -1, n = names.length;
while (++i < n) list.remove(names[i]);
}
function classedTrue(names) {
return function() {
classedAdd(this, names);
};
}
function classedFalse(names) {
return function() {
classedRemove(this, names);
};
}
function classedFunction(names, value) {
return function() {
(value.apply(this, arguments) ? classedAdd : classedRemove)(this, names);
};
}
function classed_default(name, value) {
var names = classArray(name + "");
if (arguments.length < 2) {
var list = classList(this.node()), i = -1, n = names.length;
while (++i < n) if (!list.contains(names[i])) return false;
return true;
}
return this.each((typeof value === "function" ? classedFunction : value ? classedTrue : classedFalse)(names, value));
}
//#endregion
//#region node_modules/d3-selection/src/selection/text.js
function textRemove() {
this.textContent = "";
}
function textConstant$1(value) {
return function() {
this.textContent = value;
};
}
function textFunction$1(value) {
return function() {
var v = value.apply(this, arguments);
this.textContent = v == null ? "" : v;
};
}
function text_default$1(value) {
return arguments.length ? this.each(value == null ? textRemove : (typeof value === "function" ? textFunction$1 : textConstant$1)(value)) : this.node().textContent;
}
//#endregion
//#region node_modules/d3-selection/src/selection/html.js
function htmlRemove() {
this.innerHTML = "";
}
function htmlConstant(value) {
return function() {
this.innerHTML = value;
};
}
function htmlFunction(value) {
return function() {
var v = value.apply(this, arguments);
this.innerHTML = v == null ? "" : v;
};
}
function html_default(value) {
return arguments.length ? this.each(value == null ? htmlRemove : (typeof value === "function" ? htmlFunction : htmlConstant)(value)) : this.node().innerHTML;
}
//#endregion
//#region node_modules/d3-selection/src/selection/raise.js
function raise() {
if (this.nextSibling) this.parentNode.appendChild(this);
}
function raise_default() {
return this.each(raise);
}
//#endregion
//#region node_modules/d3-selection/src/selection/lower.js
function lower() {
if (this.previousSibling) this.parentNode.insertBefore(this, this.parentNode.firstChild);
}
function lower_default() {
return this.each(lower);
}
//#endregion
//#region node_modules/d3-selection/src/selection/append.js
function append_default(name) {
var create = typeof name === "function" ? name : creator_default(name);
return this.select(function() {
return this.appendChild(create.apply(this, arguments));
});
}
//#endregion
//#region node_modules/d3-selection/src/selection/insert.js
function constantNull() {
return null;
}
function insert_default(name, before) {
var create = typeof name === "function" ? name : creator_default(name), select = before == null ? constantNull : typeof before === "function" ? before : selector_default(before);
return this.select(function() {
return this.insertBefore(create.apply(this, arguments), select.apply(this, arguments) || null);
});
}
//#endregion
//#region node_modules/d3-selection/src/selection/remove.js
function remove() {
var parent = this.parentNode;
if (parent) parent.removeChild(this);
}
function remove_default$1() {
return this.each(remove);
}
//#endregion
//#region node_modules/d3-selection/src/selection/clone.js
function selection_cloneShallow() {
var clone = this.cloneNode(false), parent = this.parentNode;
return parent ? parent.insertBefore(clone, this.nextSibling) : clone;
}
function selection_cloneDeep() {
var clone = this.cloneNode(true), parent = this.parentNode;
return parent ? parent.insertBefore(clone, this.nextSibling) : clone;
}
function clone_default(deep) {
return this.select(deep ? selection_cloneDeep : selection_cloneShallow);
}
//#endregion
//#region node_modules/d3-selection/src/selection/datum.js
function datum_default(value) {
return arguments.length ? this.property("__data__", value) : this.node().__data__;
}
//#endregion
//#region node_modules/d3-selection/src/selection/on.js
function contextListener(listener) {
return function(event) {
listener.call(this, event, this.__data__);
};
}
function parseTypenames(typenames) {
return typenames.trim().split(/^|\s+/).map(function(t) {
var name = "", i = t.indexOf(".");
if (i >= 0) name = t.slice(i + 1), t = t.slice(0, i);
return {
type: t,
name
};
});
}
function onRemove(typename) {
return function() {
var on = this.__on;
if (!on) return;
for (var j = 0, i = -1, m = on.length, o; j < m; ++j) if (o = on[j], (!typename.type || o.type === typename.type) && o.name === typename.name) this.removeEventListener(o.type, o.listener, o.options);
else on[++i] = o;
if (++i) on.length = i;
else delete this.__on;
};
}
function onAdd(typename, value, options) {
return function() {
var on = this.__on, o, listener = contextListener(value);
if (on) {
for (var j = 0, m = on.length; j < m; ++j) if ((o = on[j]).type === typename.type && o.name === typename.name) {
this.removeEventListener(o.type, o.listener, o.options);
this.addEventListener(o.type, o.listener = listener, o.options = options);
o.value = value;
return;
}
}
this.addEventListener(typename.type, listener, options);
o = {
type: typename.type,
name: typename.name,
value,
listener,
options
};
if (!on) this.__on = [o];
else on.push(o);
};
}
function on_default$1(typename, value, options) {
var typenames = parseTypenames(typename + ""), i, n = typenames.length, t;
if (arguments.length < 2) {
var on = this.node().__on;
if (on) {
for (var j = 0, m = on.length, o; j < m; ++j) for (i = 0, o = on[j]; i < n; ++i) if ((t = typenames[i]).type === o.type && t.name === o.name) return o.value;
}
return;
}
on = value ? onAdd : onRemove;
for (i = 0; i < n; ++i) this.each(on(typenames[i], value, options));
return this;
}
//#endregion
//#region node_modules/d3-selection/src/selection/dispatch.js
function dispatchEvent(node, type, params) {
var window = window_default(node), event = window.CustomEvent;
if (typeof event === "function") event = new event(type, params);
else {
event = window.document.createEvent("Event");
if (params) event.initEvent(type, params.bubbles, params.cancelable), event.detail = params.detail;
else event.initEvent(type, false, false);
}
node.dispatchEvent(event);
}
function dispatchConstant(type, params) {
return function() {
return dispatchEvent(this, type, params);
};
}
function dispatchFunction(type, params) {
return function() {
return dispatchEvent(this, type, params.apply(this, arguments));
};
}
function dispatch_default(type, params) {
return this.each((typeof params === "function" ? dispatchFunction : dispatchConstant)(type, params));
}
//#endregion
//#region node_modules/d3-selection/src/selection/iterator.js
function* iterator_default() {
for (var groups = this._groups, j = 0, m = groups.length; j < m; ++j) for (var group = groups[j], i = 0, n = group.length, node; i < n; ++i) if (node = group[i]) yield node;
}
//#endregion
//#region node_modules/d3-selection/src/selection/index.js
var root = [null];
function Selection$1(groups, parents) {
this._groups = groups;
this._parents = parents;
}
function selection() {
return new Selection$1([[document.documentElement]], root);
}
function selection_selection() {
return this;
}
Selection$1.prototype = selection.prototype = {
constructor: Selection$1,
select: select_default$2,
selectAll: selectAll_default$1,
selectChild: selectChild_default,
selectChildren: selectChildren_default,
filter: filter_default$1,
data: data_default,
enter: enter_default,
exit: exit_default,
join: join_default,
merge: merge_default$1,
selection: selection_selection,
order: order_default,
sort: sort_default,
call: call_default,
nodes: nodes_default,
node: node_default,
size: size_default,
empty: empty_default,
each: each_default,
attr: attr_default$1,
style: style_default$1,
property: property_default,
classed: classed_default,
text: text_default$1,
html: html_default,
raise: raise_default,
lower: lower_default,
append: append_default,
insert: insert_default,
remove: remove_default$1,
clone: clone_default,
datum: datum_default,
on: on_default$1,
dispatch: dispatch_default,
[Symbol.iterator]: iterator_default
};
//#endregion
//#region node_modules/d3-selection/src/select.js
function select_default$1(selector) {
return typeof selector === "string" ? new Selection$1([[document.querySelector(selector)]], [document.documentElement]) : new Selection$1([[selector]], root);
}
//#endregion
//#region node_modules/d3-selection/src/sourceEvent.js
function sourceEvent_default(event) {
let sourceEvent;
while (sourceEvent = event.sourceEvent) event = sourceEvent;
return event;
}
//#endregion
//#region node_modules/d3-selection/src/pointer.js
function pointer_default(event, node) {
event = sourceEvent_default(event);
if (node === void 0) node = event.currentTarget;
if (node) {
var svg = node.ownerSVGElement || node;
if (svg.createSVGPoint) {
var point = svg.createSVGPoint();
point.x = event.clientX, point.y = event.clientY;
point = point.matrixTransform(node.getScreenCTM().inverse());
return [point.x, point.y];
}
if (node.getBoundingClientRect) {
var rect = node.getBoundingClientRect();
return [event.clientX - rect.left - node.clientLeft, event.clientY - rect.top - node.clientTop];
}
}
return [event.pageX, event.pageY];
}
//#endregion
//#region node_modules/d3-drag/src/noevent.js
var nonpassive = { passive: false };
var nonpassivecapture = {
capture: true,
passive: false
};
function nopropagation$1(event) {
event.stopImmediatePropagation();
}
function noevent_default$1(event) {
event.preventDefault();
event.stopImmediatePropagation();
}
//#endregion
//#region node_modules/d3-drag/src/nodrag.js
function nodrag_default(view) {
var root = view.document.documentElement, selection = select_default$1(view).on("dragstart.drag", noevent_default$1, nonpassivecapture);
if ("onselectstart" in root) selection.on("selectstart.drag", noevent_default$1, nonpassivecapture);
else {
root.__noselect = root.style.MozUserSelect;
root.style.MozUserSelect = "none";
}
}
function yesdrag(view, noclick) {
var root = view.document.documentElement, selection = select_default$1(view).on("dragstart.drag", null);
if (noclick) {
selection.on("click.drag", noevent_default$1, nonpassivecapture);
setTimeout(function() {
selection.on("click.drag", null);
}, 0);
}
if ("onselectstart" in root) selection.on("selectstart.drag", null);
else {
root.style.MozUserSelect = root.__noselect;
delete root.__noselect;
}
}
//#endregion
//#region node_modules/d3-drag/src/constant.js
var constant_default$2 = (x) => () => x;
//#endregion
//#region node_modules/d3-drag/src/event.js
function DragEvent(type, { sourceEvent, subject, target, identifier, active, x, y, dx, dy, dispatch }) {
Object.defineProperties(this, {
type: {
value: type,
enumerable: true,
configurable: true
},
sourceEvent: {
value: sourceEvent,
enumerable: true,
configurable: true
},
subject: {
value: subject,
enumerable: true,
configurable: true
},
target: {
value: target,
enumerable: true,
configurable: true
},
identifier: {
value: identifier,
enumerable: true,
configurable: true
},
active: {
value: active,
enumerable: true,
configurable: true
},
x: {
value: x,
enumerable: true,
configurable: true
},
y: {
value: y,
enumerable: true,
configurable: true
},
dx: {
value: dx,
enumerable: true,
configurable: true
},
dy: {
value: dy,
enumerable: true,
configurable: true
},
_: { value: dispatch }
});
}
DragEvent.prototype.on = function() {
var value = this._.on.apply(this._, arguments);
return value === this._ ? this : value;
};
//#endregion
//#region node_modules/d3-drag/src/drag.js
function defaultFilter$1(event) {
return !event.ctrlKey && !event.button;
}
function defaultContainer() {
return this.parentNode;
}
function defaultSubject(event, d) {
return d == null ? {
x: event.x,
y: event.y
} : d;
}
function defaultTouchable$1() {
return navigator.maxTouchPoints || "ontouchstart" in this;
}
function drag_default() {
var filter = defaultFilter$1, container = defaultContainer, subject = defaultSubject, touchable = defaultTouchable$1, gestures = {}, listeners = dispatch("start", "drag", "end"), active = 0, mousedownx, mousedowny, mousemoving, touchending, clickDistance2 = 0;
function drag(selection) {
selection.on("mousedown.drag", mousedowned).filter(touchable).on("touchstart.drag", touchstarted).on("touchmove.drag", touchmoved, nonpassive).on("touchend.drag touchcancel.drag", touchended).style("touch-action", "none").style("-webkit-tap-highlight-color", "rgba(0,0,0,0)");
}
function mousedowned(event, d) {
if (touchending || !filter.call(this, event, d)) return;
var gesture = beforestart(this, container.call(this, event, d), event, d, "mouse");
if (!gesture) return;
select_default$1(event.view).on("mousemove.drag", mousemoved, nonpassivecapture).on("mouseup.drag", mouseupped, nonpassivecapture);
nodrag_default(event.view);
nopropagation$1(event);
mousemoving = false;
mousedownx = event.clientX;
mousedowny = event.clientY;
gesture("start", event);
}
function mousemoved(event) {
noevent_default$1(event);
if (!mousemoving) {
var dx = event.clientX - mousedownx, dy = event.clientY - mousedowny;
mousemoving = dx * dx + dy * dy > clickDistance2;
}
gestures.mouse("drag", event);
}
function mouseupped(event) {
select_default$1(event.view).on("mousemove.drag mouseup.drag", null);
yesdrag(event.view, mousemoving);
noevent_default$1(event);
gestures.mouse("end", event);
}
function touchstarted(event, d) {
if (!filter.call(this, event, d)) return;
var touches = event.changedTouches, c = container.call(this, event, d), n = touches.length, i, gesture;
for (i = 0; i < n; ++i) if (gesture = beforestart(this, c, event, d, touches[i].identifier, touches[i])) {
nopropagation$1(event);
gesture("start", event, touches[i]);
}
}
function touchmoved(event) {
var touches = event.changedTouches, n = touches.length, i, gesture;
for (i = 0; i < n; ++i) if (gesture = gestures[touches[i].identifier]) {
noevent_default$1(event);
gesture("drag", event, touches[i]);
}
}
function touchended(event) {
var touches = event.changedTouches, n = touches.length, i, gesture;
if (touchending) clearTimeout(touchending);
touchending = setTimeout(function() {
touchending = null;
}, 500);
for (i = 0; i < n; ++i) if (gesture = gestures[touches[i].identifier]) {
nopropagation$1(event);
gesture("end", event, touches[i]);
}
}
function beforestart(that, container, event, d, identifier, touch) {
var dispatch = listeners.copy(), p = pointer_default(touch || event, container), dx, dy, s;
if ((s = subject.call(that, new DragEvent("beforestart", {
sourceEvent: event,
target: drag,
identifier,
active,
x: p[0],
y: p[1],
dx: 0,
dy: 0,
dispatch
}), d)) == null) return;
dx = s.x - p[0] || 0;
dy = s.y - p[1] || 0;
return function gesture(type, event, touch) {
var p0 = p, n;
switch (type) {
case "start":
gestures[identifier] = gesture, n = active++;
break;
case "end": delete gestures[identifier], --active;
case "drag":
p = pointer_default(touch || event, container), n = active;
break;
}
dispatch.call(type, that, new DragEvent(type, {
sourceEvent: event,
subject: s,
target: drag,
identifier,
active: n,
x: p[0] + dx,
y: p[1] + dy,
dx: p[0] - p0[0],
dy: p[1] - p0[1],
dispatch
}), d);
};
}
drag.filter = function(_) {
return arguments.length ? (filter = typeof _ === "function" ? _ : constant_default$2(!!_), drag) : filter;
};
drag.container = function(_) {
return arguments.length ? (container = typeof _ === "function" ? _ : constant_default$2(_), drag) : container;
};
drag.subject = function(_) {
return arguments.length ? (subject = typeof _ === "function" ? _ : constant_default$2(_), drag) : subject;
};
drag.touchable = function(_) {
return arguments.length ? (touchable = typeof _ === "function" ? _ : constant_default$2(!!_), drag) : touchable;
};
drag.on = function() {
var value = listeners.on.apply(listeners, arguments);
return value === listeners ? drag : value;
};
drag.clickDistance = function(_) {
return arguments.length ? (clickDistance2 = (_ = +_) * _, drag) : Math.sqrt(clickDistance2);
};
return drag;
}
//#endregion
//#region node_modules/d3-color/src/define.js
function define_default(constructor, factory, prototype) {
constructor.prototype = factory.prototype = prototype;
prototype.constructor = constructor;
}
function extend(parent, definition) {
var prototype = Object.create(parent.prototype);
for (var key in definition) prototype[key] = definition[key];
return prototype;
}
//#endregion
//#region node_modules/d3-color/src/color.js
function Color() {}
var darker = .7;
var brighter = 1 / darker;
var reI = "\\s*([+-]?\\d+)\\s*", reN = "\\s*([+-]?(?:\\d*\\.)?\\d+(?:[eE][+-]?\\d+)?)\\s*", reP = "\\s*([+-]?(?:\\d*\\.)?\\d+(?:[eE][+-]?\\d+)?)%\\s*", reHex = /^#([0-9a-f]{3,8})$/, reRgbInteger = new RegExp(`^rgb\\(${reI},${reI},${reI}\\)$`), reRgbPercent = new RegExp(`^rgb\\(${reP},${reP},${reP}\\)$`), reRgbaInteger = new RegExp(`^rgba\\(${reI},${reI},${reI},${reN}\\)$`), reRgbaPercent = new RegExp(`^rgba\\(${reP},${reP},${reP},${reN}\\)$`), reHslPercent = new RegExp(`^hsl\\(${reN},${reP},${reP}\\)$`), reHslaPercent = new RegExp(`^hsla\\(${reN},${reP},${reP},${reN}\\)$`);
var named = {
aliceblue: 15792383,
antiquewhite: 16444375,
aqua: 65535,
aquamarine: 8388564,
azure: 15794175,
beige: 16119260,
bisque: 16770244,
black: 0,
blanchedalmond: 16772045,
blue: 255,
blueviolet: 9055202,
brown: 10824234,
burlywood: 14596231,
cadetblue: 6266528,
chartreuse: 8388352,
chocolate: 13789470,
coral: 16744272,
cornflowerblue: 6591981,
cornsilk: 16775388,
crimson: 14423100,
cyan: 65535,
darkblue: 139,
darkcyan: 35723,
darkgoldenrod: 12092939,
darkgray: 11119017,
darkgreen: 25600,
darkgrey: 11119017,
darkkhaki: 12433259,
darkmagenta: 9109643,
darkolivegreen: 5597999,
darkorange: 16747520,
darkorchid: 10040012,
darkred: 9109504,
darksalmon: 15308410,
darkseagreen: 9419919,
darkslateblue: 4734347,
darkslategray: 3100495,
darkslategrey: 3100495,
darkturquoise: 52945,
darkviolet: 9699539,
deeppink: 16716947,
deepskyblue: 49151,
dimgray: 6908265,
dimgrey: 6908265,
dodgerblue: 2003199,
firebrick: 11674146,
floralwhite: 16775920,
forestgreen: 2263842,
fuchsia: 16711935,
gainsboro: 14474460,
ghostwhite: 16316671,
gold: 16766720,
goldenrod: 14329120,
gray: 8421504,
green: 32768,
greenyellow: 11403055,
grey: 8421504,
honeydew: 15794160,
hotpink: 16738740,
indianred: 13458524,
indigo: 4915330,
ivory: 16777200,
khaki: 15787660,
lavender: 15132410,
lavenderblush: 16773365,
lawngreen: 8190976,
lemonchiffon: 16775885,
lightblue: 11393254,
lightcoral: 15761536,
lightcyan: 14745599,
lightgoldenrodyellow: 16448210,
lightgray: 13882323,
lightgreen: 9498256,
lightgrey: 13882323,
lightpink: 16758465,
lightsalmon: 16752762,
lightseagreen: 2142890,
lightskyblue: 8900346,
lightslategray: 7833753,
lightslategrey: 7833753,
lightsteelblue: 11584734,
lightyellow: 16777184,
lime: 65280,
limegreen: 3329330,
linen: 16445670,
magenta: 16711935,
maroon: 8388608,
mediumaquamarine: 6737322,
mediumblue: 205,
mediumorchid: 12211667,
mediumpurple: 9662683,
mediumseagreen: 3978097,
mediumslateblue: 8087790,
mediumspringgreen: 64154,
mediumturquoise: 4772300,
mediumvioletred: 13047173,
midnightblue: 1644912,
mintcream: 16121850,
mistyrose: 16770273,
moccasin: 16770229,
navajowhite: 16768685,
navy: 128,
oldlace: 16643558,
olive: 8421376,
olivedrab: 7048739,
orange: 16753920,
orangered: 16729344,
orchid: 14315734,
palegoldenrod: 15657130,
palegreen: 10025880,
paleturquoise: 11529966,
palevioletred: 14381203,
papayawhip: 16773077,
peachpuff: 16767673,
peru: 13468991,
pink: 16761035,
plum: 14524637,
powderblue: 11591910,
purple: 8388736,
rebeccapurple: 6697881,
red: 16711680,
rosybrown: 12357519,
royalblue: 4286945,
saddlebrown: 9127187,
salmon: 16416882,
sandybrown: 16032864,
seagreen: 3050327,
seashell: 16774638,
sienna: 10506797,
silver: 12632256,
skyblue: 8900331,
slateblue: 6970061,
slategray: 7372944,
slategrey: 7372944,
snow: 16775930,
springgreen: 65407,
steelblue: 4620980,
tan: 13808780,
teal: 32896,
thistle: 14204888,
tomato: 16737095,
turquoise: 4251856,
violet: 15631086,
wheat: 16113331,
white: 16777215,
whitesmoke: 16119285,
yellow: 16776960,
yellowgreen: 10145074
};
define_default(Color, color, {
copy(channels) {
return Object.assign(new this.constructor(), this, channels);
},
displayable() {
return this.rgb().displayable();
},
hex: color_formatHex,
formatHex: color_formatHex,
formatHex8: color_formatHex8,
formatHsl: color_formatHsl,
formatRgb: color_formatRgb,
toString: color_formatRgb
});
function color_formatHex() {
return this.rgb().formatHex();
}
function color_formatHex8() {
return this.rgb().formatHex8();
}
function color_formatHsl() {
return hslConvert(this).formatHsl();
}
function color_formatRgb() {
return this.rgb().formatRgb();
}
function color(format) {
var m, l;
format = (format + "").trim().toLowerCase();
return (m = reHex.exec(format)) ? (l = m[1].length, m = parseInt(m[1], 16), l === 6 ? rgbn(m) : l === 3 ? new Rgb(m >> 8 & 15 | m >> 4 & 240, m >> 4 & 15 | m & 240, (m & 15) << 4 | m & 15, 1) : l === 8 ? rgba(m >> 24 & 255, m >> 16 & 255, m >> 8 & 255, (m & 255) / 255) : l === 4 ? rgba(m >> 12 & 15 | m >> 8 & 240, m >> 8 & 15 | m >> 4 & 240, m >> 4 & 15 | m & 240, ((m & 15) << 4 | m & 15) / 255) : null) : (m = reRgbInteger.exec(format)) ? new Rgb(m[1], m[2], m[3], 1) : (m = reRgbPercent.exec(format)) ? new Rgb(m[1] * 255 / 100, m[2] * 255 / 100, m[3] * 255 / 100, 1) : (m = reRgbaInteger.exec(format)) ? rgba(m[1], m[2], m[3], m[4]) : (m = reRgbaPercent.exec(format)) ? rgba(m[1] * 255 / 100, m[2] * 255 / 100, m[3] * 255 / 100, m[4]) : (m = reHslPercent.exec(format)) ? hsla(m[1], m[2] / 100, m[3] / 100, 1) : (m = reHslaPercent.exec(format)) ? hsla(m[1], m[2] / 100, m[3] / 100, m[4]) : named.hasOwnProperty(format) ? rgbn(named[format]) : format === "transparent" ? new Rgb(NaN, NaN, NaN, 0) : null;
}
function rgbn(n) {
return new Rgb(n >> 16 & 255, n >> 8 & 255, n & 255, 1);
}
function rgba(r, g, b, a) {
if (a <= 0) r = g = b = NaN;
return new Rgb(r, g, b, a);
}
function rgbConvert(o) {
if (!(o instanceof Color)) o = color(o);
if (!o) return new Rgb();
o = o.rgb();
return new Rgb(o.r, o.g, o.b, o.opacity);
}
function rgb(r, g, b, opacity) {
return arguments.length === 1 ? rgbConvert(r) : new Rgb(r, g, b, opacity == null ? 1 : opacity);
}
function Rgb(r, g, b, opacity) {
this.r = +r;
this.g = +g;
this.b = +b;
this.opacity = +opacity;
}
define_default(Rgb, rgb, extend(Color, {
brighter(k) {
k = k == null ? brighter : Math.pow(brighter, k);
return new Rgb(this.r * k, this.g * k, this.b * k, this.opacity);
},
darker(k) {
k = k == null ? darker : Math.pow(darker, k);
return new Rgb(this.r * k, this.g * k, this.b * k, this.opacity);
},
rgb() {
return this;
},
clamp() {
return new Rgb(clampi(this.r), clampi(this.g), clampi(this.b), clampa(this.opacity));
},
displayable() {
return -.5 <= this.r && this.r < 255.5 && -.5 <= this.g && this.g < 255.5 && -.5 <= this.b && this.b < 255.5 && 0 <= this.opacity && this.opacity <= 1;
},
hex: rgb_formatHex,
formatHex: rgb_formatHex,
formatHex8: rgb_formatHex8,
formatRgb: rgb_formatRgb,
toString: rgb_formatRgb
}));
function rgb_formatHex() {
return `#${hex(this.r)}${hex(this.g)}${hex(this.b)}`;
}
function rgb_formatHex8() {
return `#${hex(this.r)}${hex(this.g)}${hex(this.b)}${hex((isNaN(this.opacity) ? 1 : this.opacity) * 255)}`;
}
function rgb_formatRgb() {
const a = clampa(this.opacity);
return `${a === 1 ? "rgb(" : "rgba("}${clampi(this.r)}, ${clampi(this.g)}, ${clampi(this.b)}${a === 1 ? ")" : `, ${a})`}`;
}
function clampa(opacity) {
return isNaN(opacity) ? 1 : Math.max(0, Math.min(1, opacity));
}
function clampi(value) {
return Math.max(0, Math.min(255, Math.round(value) || 0));
}
function hex(value) {
value = clampi(value);
return (value < 16 ? "0" : "") + value.toString(16);
}
function hsla(h, s, l, a) {
if (a <= 0) h = s = l = NaN;
else if (l <= 0 || l >= 1) h = s = NaN;
else if (s <= 0) h = NaN;
return new Hsl(h, s, l, a);
}
function hslConvert(o) {
if (o instanceof Hsl) return new Hsl(o.h, o.s, o.l, o.opacity);
if (!(o instanceof Color)) o = color(o);
if (!o) return new Hsl();
if (o instanceof Hsl) return o;
o = o.rgb();
var r = o.r / 255, g = o.g / 255, b = o.b / 255, min = Math.min(r, g, b), max = Math.max(r, g, b), h = NaN, s = max - min, l = (max + min) / 2;
if (s) {
if (r === max) h = (g - b) / s + (g < b) * 6;
else if (g === max) h = (b - r) / s + 2;
else h = (r - g) / s + 4;
s /= l < .5 ? max + min : 2 - max - min;
h *= 60;
} else s = l > 0 && l < 1 ? 0 : h;
return new Hsl(h, s, l, o.opacity);
}
function hsl(h, s, l, opacity) {
return arguments.length === 1 ? hslConvert(h) : new Hsl(h, s, l, opacity == null ? 1 : opacity);
}
function Hsl(h, s, l, opacity) {
this.h = +h;
this.s = +s;
this.l = +l;
this.opacity = +opacity;
}
define_default(Hsl, hsl, extend(Color, {
brighter(k) {
k = k == null ? brighter : Math.pow(brighter, k);
return new Hsl(this.h, this.s, this.l * k, this.opacity);
},
darker(k) {
k = k == null ? darker : Math.pow(darker, k);
return new Hsl(this.h, this.s, this.l * k, this.opacity);
},
rgb() {
var h = this.h % 360 + (this.h < 0) * 360, s = isNaN(h) || isNaN(this.s) ? 0 : this.s, l = this.l, m2 = l + (l < .5 ? l : 1 - l) * s, m1 = 2 * l - m2;
return new Rgb(hsl2rgb(h >= 240 ? h - 240 : h + 120, m1, m2), hsl2rgb(h, m1, m2), hsl2rgb(h < 120 ? h + 240 : h - 120, m1, m2), this.opacity);
},
clamp() {
return new Hsl(clamph(this.h), clampt(this.s), clampt(this.l), clampa(this.opacity));
},
displayable() {
return (0 <= this.s && this.s <= 1 || isNaN(this.s)) && 0 <= this.l && this.l <= 1 && 0 <= this.opacity && this.opacity <= 1;
},
formatHsl() {
const a = clampa(this.opacity);
return `${a === 1 ? "hsl(" : "hsla("}${clamph(this.h)}, ${clampt(this.s) * 100}%, ${clampt(this.l) * 100}%${a === 1 ? ")" : `, ${a})`}`;
}
}));
function clamph(value) {
value = (value || 0) % 360;
return value < 0 ? value + 360 : value;
}
function clampt(value) {
return Math.max(0, Math.min(1, value || 0));
}
function hsl2rgb(h, m1, m2) {
return (h < 60 ? m1 + (m2 - m1) * h / 60 : h < 180 ? m2 : h < 240 ? m1 + (m2 - m1) * (240 - h) / 60 : m1) * 255;
}
//#endregion
//#region node_modules/d3-interpolate/src/constant.js
var constant_default$1 = (x) => () => x;
//#endregion
//#region node_modules/d3-interpolate/src/color.js
function linear(a, d) {
return function(t) {
return a + t * d;
};
}
function exponential(a, b, y) {
return a = Math.pow(a, y), b = Math.pow(b, y) - a, y = 1 / y, function(t) {
return Math.pow(a + t * b, y);
};
}
function gamma(y) {
return (y = +y) === 1 ? nogamma : function(a, b) {
return b - a ? exponential(a, b, y) : constant_default$1(isNaN(a) ? b : a);
};
}
function nogamma(a, b) {
var d = b - a;
return d ? linear(a, d) : constant_default$1(isNaN(a) ? b : a);
}
//#endregion
//#region node_modules/d3-interpolate/src/rgb.js
var rgb_default = (function rgbGamma(y) {
var color = gamma(y);
function rgb$1(start, end) {
var r = color((start = rgb(start)).r, (end = rgb(end)).r), g = color(start.g, end.g), b = color(start.b, end.b), opacity = nogamma(start.opacity, end.opacity);
return function(t) {
start.r = r(t);
start.g = g(t);
start.b = b(t);
start.opacity = opacity(t);
return start + "";
};
}
rgb$1.gamma = rgbGamma;
return rgb$1;
})(1);
//#endregion
//#region node_modules/d3-interpolate/src/numberArray.js
function numberArray_default(a, b) {
if (!b) b = [];
var n = a ? Math.min(b.length, a.length) : 0, c = b.slice(), i;
return function(t) {
for (i = 0; i < n; ++i) c[i] = a[i] * (1 - t) + b[i] * t;
return c;
};
}
function isNumberArray(x) {
return ArrayBuffer.isView(x) && !(x instanceof DataView);
}
//#endregion
//#region node_modules/d3-interpolate/src/array.js
function genericArray(a, b) {
var nb = b ? b.length : 0, na = a ? Math.min(nb, a.length) : 0, x = new Array(na), c = new Array(nb), i;
for (i = 0; i < na; ++i) x[i] = value_default(a[i], b[i]);
for (; i < nb; ++i) c[i] = b[i];
return function(t) {
for (i = 0; i < na; ++i) c[i] = x[i](t);
return c;
};
}
//#endregion
//#region node_modules/d3-interpolate/src/date.js
function date_default(a, b) {
var d = /* @__PURE__ */ new Date();
return a = +a, b = +b, function(t) {
return d.setTime(a * (1 - t) + b * t), d;
};
}
//#endregion
//#region node_modules/d3-interpolate/src/number.js
function number_default(a, b) {
return a = +a, b = +b, function(t) {
return a * (1 - t) + b * t;
};
}
//#endregion
//#region node_modules/d3-interpolate/src/object.js
function object_default(a, b) {
var i = {}, c = {}, k;
if (a === null || typeof a !== "object") a = {};
if (b === null || typeof b !== "object") b = {};
for (k in b) if (k in a) i[k] = value_default(a[k], b[k]);
else c[k] = b[k];
return function(t) {
for (k in i) c[k] = i[k](t);
return c;
};
}
//#endregion
//#region node_modules/d3-interpolate/src/string.js
var reA = /[-+]?(?:\d+\.?\d*|\.?\d+)(?:[eE][-+]?\d+)?/g, reB = new RegExp(reA.source, "g");
function zero(b) {
return function() {
return b;
};
}
function one(b) {
return function(t) {
return b(t) + "";
};
}
function string_default(a, b) {
var bi = reA.lastIndex = reB.lastIndex = 0, am, bm, bs, i = -1, s = [], q = [];
a = a + "", b = b + "";
while ((am = reA.exec(a)) && (bm = reB.exec(b))) {
if ((bs = bm.index) > bi) {
bs = b.slice(bi, bs);
if (s[i]) s[i] += bs;
else s[++i] = bs;
}
if ((am = am[0]) === (bm = bm[0])) if (s[i]) s[i] += bm;
else s[++i] = bm;
else {
s[++i] = null;
q.push({
i,
x: number_default(am, bm)
});
}
bi = reB.lastIndex;
}
if (bi < b.length) {
bs = b.slice(bi);
if (s[i]) s[i] += bs;
else s[++i] = bs;
}
return s.length < 2 ? q[0] ? one(q[0].x) : zero(b) : (b = q.length, function(t) {
for (var i = 0, o; i < b; ++i) s[(o = q[i]).i] = o.x(t);
return s.join("");
});
}
//#endregion
//#region node_modules/d3-interpolate/src/value.js
function value_default(a, b) {
var t = typeof b, c;
return b == null || t === "boolean" ? constant_default$1(b) : (t === "number" ? number_default : t === "string" ? (c = color(b)) ? (b = c, rgb_default) : string_default : b instanceof color ? rgb_default : b instanceof Date ? date_default : isNumberArray(b) ? numberArray_default : Array.isArray(b) ? genericArray : typeof b.valueOf !== "function" && typeof b.toString !== "function" || isNaN(b) ? object_default : number_default)(a, b);
}
//#endregion
//#region node_modules/d3-interpolate/src/transform/decompose.js
var degrees = 180 / Math.PI;
var identity$2 = {
translateX: 0,
translateY: 0,
rotate: 0,
skewX: 0,
scaleX: 1,
scaleY: 1
};
function decompose_default(a, b, c, d, e, f) {
var scaleX, scaleY, skewX;
if (scaleX = Math.sqrt(a * a + b * b)) a /= scaleX, b /= scaleX;
if (skewX = a * c + b * d) c -= a * skewX, d -= b * skewX;
if (scaleY = Math.sqrt(c * c + d * d)) c /= scaleY, d /= scaleY, skewX /= scaleY;
if (a * d < b * c) a = -a, b = -b, skewX = -skewX, scaleX = -scaleX;
return {
translateX: e,
translateY: f,
rotate: Math.atan2(b, a) * degrees,
skewX: Math.atan(skewX) * degrees,
scaleX,
scaleY
};
}
//#endregion
//#region node_modules/d3-interpolate/src/transform/parse.js
var svgNode;
function parseCss(value) {
const m = new (typeof DOMMatrix === "function" ? DOMMatrix : WebKitCSSMatrix)(value + "");
return m.isIdentity ? identity$2 : decompose_default(m.a, m.b, m.c, m.d, m.e, m.f);
}
function parseSvg(value) {
if (value == null) return identity$2;
if (!svgNode) svgNode = document.createElementNS("http://www.w3.org/2000/svg", "g");
svgNode.setAttribute("transform", value);
if (!(value = svgNode.transform.baseVal.consolidate())) return identity$2;
value = value.matrix;
return decompose_default(value.a, value.b, value.c, value.d, value.e, value.f);
}
//#endregion
//#region node_modules/d3-interpolate/src/transform/index.js
function interpolateTransform(parse, pxComma, pxParen, degParen) {
function pop(s) {
return s.length ? s.pop() + " " : "";
}
function translate(xa, ya, xb, yb, s, q) {
if (xa !== xb || ya !== yb) {
var i = s.push("translate(", null, pxComma, null, pxParen);
q.push({
i: i - 4,
x: number_default(xa, xb)
}, {
i: i - 2,
x: number_default(ya, yb)
});
} else if (xb || yb) s.push("translate(" + xb + pxComma + yb + pxParen);
}
function rotate(a, b, s, q) {
if (a !== b) {
if (a - b > 180) b += 360;
else if (b - a > 180) a += 360;
q.push({
i: s.push(pop(s) + "rotate(", null, degParen) - 2,
x: number_default(a, b)
});
} else if (b) s.push(pop(s) + "rotate(" + b + degParen);
}
function skewX(a, b, s, q) {
if (a !== b) q.push({
i: s.push(pop(s) + "skewX(", null, degParen) - 2,
x: number_default(a, b)
});
else if (b) s.push(pop(s) + "skewX(" + b + degParen);
}
function scale(xa, ya, xb, yb, s, q) {
if (xa !== xb || ya !== yb) {
var i = s.push(pop(s) + "scale(", null, ",", null, ")");
q.push({
i: i - 4,
x: number_default(xa, xb)
}, {
i: i - 2,
x: number_default(ya, yb)
});
} else if (xb !== 1 || yb !== 1) s.push(pop(s) + "scale(" + xb + "," + yb + ")");
}
return function(a, b) {
var s = [], q = [];
a = parse(a), b = parse(b);
translate(a.translateX, a.translateY, b.translateX, b.translateY, s, q);
rotate(a.rotate, b.rotate, s, q);
skewX(a.skewX, b.skewX, s, q);
scale(a.scaleX, a.scaleY, b.scaleX, b.scaleY, s, q);
a = b = null;
return function(t) {
var i = -1, n = q.length, o;
while (++i < n) s[(o = q[i]).i] = o.x(t);
return s.join("");
};
};
}
var interpolateTransformCss = interpolateTransform(parseCss, "px, ", "px)", "deg)");
var interpolateTransformSvg = interpolateTransform(parseSvg, ", ", ")", ")");
//#endregion
//#region node_modules/d3-interpolate/src/zoom.js
var epsilon2 = 1e-12;
function cosh(x) {
return ((x = Math.exp(x)) + 1 / x) / 2;
}
function sinh(x) {
return ((x = Math.exp(x)) - 1 / x) / 2;
}
function tanh(x) {
return ((x = Math.exp(2 * x)) - 1) / (x + 1);
}
var zoom_default$1 = (function zoomRho(rho, rho2, rho4) {
function zoom(p0, p1) {
var ux0 = p0[0], uy0 = p0[1], w0 = p0[2], ux1 = p1[0], uy1 = p1[1], w1 = p1[2], dx = ux1 - ux0, dy = uy1 - uy0, d2 = dx * dx + dy * dy, i, S;
if (d2 < epsilon2) {
S = Math.log(w1 / w0) / rho;
i = function(t) {
return [
ux0 + t * dx,
uy0 + t * dy,
w0 * Math.exp(rho * t * S)
];
};
} else {
var d1 = Math.sqrt(d2), b0 = (w1 * w1 - w0 * w0 + rho4 * d2) / (2 * w0 * rho2 * d1), b1 = (w1 * w1 - w0 * w0 - rho4 * d2) / (2 * w1 * rho2 * d1), r0 = Math.log(Math.sqrt(b0 * b0 + 1) - b0);
S = (Math.log(Math.sqrt(b1 * b1 + 1) - b1) - r0) / rho;
i = function(t) {
var s = t * S, coshr0 = cosh(r0), u = w0 / (rho2 * d1) * (coshr0 * tanh(rho * s + r0) - sinh(r0));
return [
ux0 + u * dx,
uy0 + u * dy,
w0 * coshr0 / cosh(rho * s + r0)
];
};
}
i.duration = S * 1e3 * rho / Math.SQRT2;
return i;
}
zoom.rho = function(_) {
var _1 = Math.max(.001, +_), _2 = _1 * _1;
return zoomRho(_1, _2, _2 * _2);
};
return zoom;
})(Math.SQRT2, 2, 4);
//#endregion
//#region node_modules/d3-timer/src/timer.js
var frame = 0, timeout = 0, interval = 0, pokeDelay = 1e3, taskHead, taskTail, clockLast = 0, clockNow = 0, clockSkew = 0, clock = typeof performance === "object" && performance.now ? performance : Date, setFrame = typeof window === "object" && window.requestAnimationFrame ? window.requestAnimationFrame.bind(window) : function(f) {
setTimeout(f, 17);
};
function now() {
return clockNow || (setFrame(clearNow), clockNow = clock.now() + clockSkew);
}
function clearNow() {
clockNow = 0;
}
function Timer() {
this._call = this._time = this._next = null;
}
Timer.prototype = timer.prototype = {
constructor: Timer,
restart: function(callback, delay, time) {
if (typeof callback !== "function") throw new TypeError("callback is not a function");
time = (time == null ? now() : +time) + (delay == null ? 0 : +delay);
if (!this._next && taskTail !== this) {
if (taskTail) taskTail._next = this;
else taskHead = this;
taskTail = this;
}
this._call = callback;
this._time = time;
sleep();
},
stop: function() {
if (this._call) {
this._call = null;
this._time = Infinity;
sleep();
}
}
};
function timer(callback, delay, time) {
var t = new Timer();
t.restart(callback, delay, time);
return t;
}
function timerFlush() {
now();
++frame;
var t = taskHead, e;
while (t) {
if ((e = clockNow - t._time) >= 0) t._call.call(void 0, e);
t = t._next;
}
--frame;
}
function wake() {
clockNow = (clockLast = clock.now()) + clockSkew;
frame = timeout = 0;
try {
timerFlush();
} finally {
frame = 0;
nap();
clockNow = 0;
}
}
function poke() {
var now = clock.now(), delay = now - clockLast;
if (delay > pokeDelay) clockSkew -= delay, clockLast = now;
}
function nap() {
var t0, t1 = taskHead, t2, time = Infinity;
while (t1) if (t1._call) {
if (time > t1._time) time = t1._time;
t0 = t1, t1 = t1._next;
} else {
t2 = t1._next, t1._next = null;
t1 = t0 ? t0._next = t2 : taskHead = t2;
}
taskTail = t0;
sleep(time);
}
function sleep(time) {
if (frame) return;
if (timeout) timeout = clearTimeout(timeout);
if (time - clockNow > 24) {
if (time < Infinity) timeout = setTimeout(wake, time - clock.now() - clockSkew);
if (interval) interval = clearInterval(interval);
} else {
if (!interval) clockLast = clock.now(), interval = setInterval(poke, pokeDelay);
frame = 1, setFrame(wake);
}
}
//#endregion
//#region node_modules/d3-timer/src/timeout.js
function timeout_default(callback, delay, time) {
var t = new Timer();
delay = delay == null ? 0 : +delay;
t.restart((elapsed) => {
t.stop();
callback(elapsed + delay);
}, delay, time);
return t;
}
//#endregion
//#region node_modules/d3-transition/src/transition/schedule.js
var emptyOn = dispatch("start", "end", "cancel", "interrupt");
var emptyTween = [];
function schedule_default(node, name, id, index, group, timing) {
var schedules = node.__transition;
if (!schedules) node.__transition = {};
else if (id in schedules) return;
create(node, id, {
name,
index,
group,
on: emptyOn,
tween: emptyTween,
time: timing.time,
delay: timing.delay,
duration: timing.duration,
ease: timing.ease,
timer: null,
state: 0
});
}
function init(node, id) {
var schedule = get(node, id);
if (schedule.state > 0) throw new Error("too late; already scheduled");
return schedule;
}
function set(node, id) {
var schedule = get(node, id);
if (schedule.state > 3) throw new Error("too late; already running");
return schedule;
}
function get(node, id) {
var schedule = node.__transition;
if (!schedule || !(schedule = schedule[id])) throw new Error("transition not found");
return schedule;
}
function create(node, id, self) {
var schedules = node.__transition, tween;
schedules[id] = self;
self.timer = timer(schedule, 0, self.time);
function schedule(elapsed) {
self.state = 1;
self.timer.restart(start, self.delay, self.time);
if (self.delay <= elapsed) start(elapsed - self.delay);
}
function start(elapsed) {
var i, j, n, o;
if (self.state !== 1) return stop();
for (i in schedules) {
o = schedules[i];
if (o.name !== self.name) continue;
if (o.state === 3) return timeout_default(start);
if (o.state === 4) {
o.state = 6;
o.timer.stop();
o.on.call("interrupt", node, node.__data__, o.index, o.group);
delete schedules[i];
} else if (+i < id) {
o.state = 6;
o.timer.stop();
o.on.call("cancel", node, node.__data__, o.index, o.group);
delete schedules[i];
}
}
timeout_default(function() {
if (self.state === 3) {
self.state = 4;
self.timer.restart(tick, self.delay, self.time);
tick(elapsed);
}
});
self.state = 2;
self.on.call("start", node, node.__data__, self.index, self.group);
if (self.state !== 2) return;
self.state = 3;
tween = new Array(n = self.tween.length);
for (i = 0, j = -1; i < n; ++i) if (o = self.tween[i].value.call(node, node.__data__, self.index, self.group)) tween[++j] = o;
tween.length = j + 1;
}
function tick(elapsed) {
var t = elapsed < self.duration ? self.ease.call(null, elapsed / self.duration) : (self.timer.restart(stop), self.state = 5, 1), i = -1, n = tween.length;
while (++i < n) tween[i].call(node, t);
if (self.state === 5) {
self.on.call("end", node, node.__data__, self.index, self.group);
stop();
}
}
function stop() {
self.state = 6;
self.timer.stop();
delete schedules[id];
for (var i in schedules) return;
delete node.__transition;
}
}
//#endregion
//#region node_modules/d3-transition/src/interrupt.js
function interrupt_default$1(node, name) {
var schedules = node.__transition, schedule, active, empty = true, i;
if (!schedules) return;
name = name == null ? null : name + "";
for (i in schedules) {
if ((schedule = schedules[i]).name !== name) {
empty = false;
continue;
}
active = schedule.state > 2 && schedule.state < 5;
schedule.state = 6;
schedule.timer.stop();
schedule.on.call(active ? "interrupt" : "cancel", node, node.__data__, schedule.index, schedule.group);
delete schedules[i];
}
if (empty) delete node.__transition;
}
//#endregion
//#region node_modules/d3-transition/src/selection/interrupt.js
function interrupt_default(name) {
return this.each(function() {
interrupt_default$1(this, name);
});
}
//#endregion
//#region node_modules/d3-transition/src/transition/tween.js
function tweenRemove(id, name) {
var tween0, tween1;
return function() {
var schedule = set(this, id), tween = schedule.tween;
if (tween !== tween0) {
tween1 = tween0 = tween;
for (var i = 0, n = tween1.length; i < n; ++i) if (tween1[i].name === name) {
tween1 = tween1.slice();
tween1.splice(i, 1);
break;
}
}
schedule.tween = tween1;
};
}
function tweenFunction(id, name, value) {
var tween0, tween1;
if (typeof value !== "function") throw new Error();
return function() {
var schedule = set(this, id), tween = schedule.tween;
if (tween !== tween0) {
tween1 = (tween0 = tween).slice();
for (var t = {
name,
value
}, i = 0, n = tween1.length; i < n; ++i) if (tween1[i].name === name) {
tween1[i] = t;
break;
}
if (i === n) tween1.push(t);
}
schedule.tween = tween1;
};
}
function tween_default(name, value) {
var id = this._id;
name += "";
if (arguments.length < 2) {
var tween = get(this.node(), id).tween;
for (var i = 0, n = tween.length, t; i < n; ++i) if ((t = tween[i]).name === name) return t.value;
return null;
}
return this.each((value == null ? tweenRemove : tweenFunction)(id, name, value));
}
function tweenValue(transition, name, value) {
var id = transition._id;
transition.each(function() {
var schedule = set(this, id);
(schedule.value || (schedule.value = {}))[name] = value.apply(this, arguments);
});
return function(node) {
return get(node, id).value[name];
};
}
//#endregion
//#region node_modules/d3-transition/src/transition/interpolate.js
function interpolate_default(a, b) {
var c;
return (typeof b === "number" ? number_default : b instanceof color ? rgb_default : (c = color(b)) ? (b = c, rgb_default) : string_default)(a, b);
}
//#endregion
//#region node_modules/d3-transition/src/transition/attr.js
function attrRemove(name) {
return function() {
this.removeAttribute(name);
};
}
function attrRemoveNS(fullname) {
return function() {
this.removeAttributeNS(fullname.space, fullname.local);
};
}
function attrConstant(name, interpolate, value1) {
var string00, string1 = value1 + "", interpolate0;
return function() {
var string0 = this.getAttribute(name);
return string0 === string1 ? null : string0 === string00 ? interpolate0 : interpolate0 = interpolate(string00 = string0, value1);
};
}
function attrConstantNS(fullname, interpolate, value1) {
var string00, string1 = value1 + "", interpolate0;
return function() {
var string0 = this.getAttributeNS(fullname.space, fullname.local);
return string0 === string1 ? null : string0 === string00 ? interpolate0 : interpolate0 = interpolate(string00 = string0, value1);
};
}
function attrFunction(name, interpolate, value) {
var string00, string10, interpolate0;
return function() {
var string0, value1 = value(this), string1;
if (value1 == null) return void this.removeAttribute(name);
string0 = this.getAttribute(name);
string1 = value1 + "";
return string0 === string1 ? null : string0 === string00 && string1 === string10 ? interpolate0 : (string10 = string1, interpolate0 = interpolate(string00 = string0, value1));
};
}
function attrFunctionNS(fullname, interpolate, value) {
var string00, string10, interpolate0;
return function() {
var string0, value1 = value(this), string1;
if (value1 == null) return void this.removeAttributeNS(fullname.space, fullname.local);
string0 = this.getAttributeNS(fullname.space, fullname.local);
string1 = value1 + "";
return string0 === string1 ? null : string0 === string00 && string1 === string10 ? interpolate0 : (string10 = string1, interpolate0 = interpolate(string00 = string0, value1));
};
}
function attr_default(name, value) {
var fullname = namespace_default(name), i = fullname === "transform" ? interpolateTransformSvg : interpolate_default;
return this.attrTween(name, typeof value === "function" ? (fullname.local ? attrFunctionNS : attrFunction)(fullname, i, tweenValue(this, "attr." + name, value)) : value == null ? (fullname.local ? attrRemoveNS : attrRemove)(fullname) : (fullname.local ? attrConstantNS : attrConstant)(fullname, i, value));
}
//#endregion
//#region node_modules/d3-transition/src/transition/attrTween.js
function attrInterpolate(name, i) {
return function(t) {
this.setAttribute(name, i.call(this, t));
};
}
function attrInterpolateNS(fullname, i) {
return function(t) {
this.setAttributeNS(fullname.space, fullname.local, i.call(this, t));
};
}
function attrTweenNS(fullname, value) {
var t0, i0;
function tween() {
var i = value.apply(this, arguments);
if (i !== i0) t0 = (i0 = i) && attrInterpolateNS(fullname, i);
return t0;
}
tween._value = value;
return tween;
}
function attrTween(name, value) {
var t0, i0;
function tween() {
var i = value.apply(this, arguments);
if (i !== i0) t0 = (i0 = i) && attrInterpolate(name, i);
return t0;
}
tween._value = value;
return tween;
}
function attrTween_default(name, value) {
var key = "attr." + name;
if (arguments.length < 2) return (key = this.tween(key)) && key._value;
if (value == null) return this.tween(key, null);
if (typeof value !== "function") throw new Error();
var fullname = namespace_default(name);
return this.tween(key, (fullname.local ? attrTweenNS : attrTween)(fullname, value));
}
//#endregion
//#region node_modules/d3-transition/src/transition/delay.js
function delayFunction(id, value) {
return function() {
init(this, id).delay = +value.apply(this, arguments);
};
}
function delayConstant(id, value) {
return value = +value, function() {
init(this, id).delay = value;
};
}
function delay_default(value) {
var id = this._id;
return arguments.length ? this.each((typeof value === "function" ? delayFunction : delayConstant)(id, value)) : get(this.node(), id).delay;
}
//#endregion
//#region node_modules/d3-transition/src/transition/duration.js
function durationFunction(id, value) {
return function() {
set(this, id).duration = +value.apply(this, arguments);
};
}
function durationConstant(id, value) {
return value = +value, function() {
set(this, id).duration = value;
};
}
function duration_default(value) {
var id = this._id;
return arguments.length ? this.each((typeof value === "function" ? durationFunction : durationConstant)(id, value)) : get(this.node(), id).duration;
}
//#endregion
//#region node_modules/d3-transition/src/transition/ease.js
function easeConstant(id, value) {
if (typeof value !== "function") throw new Error();
return function() {
set(this, id).ease = value;
};
}
function ease_default(value) {
var id = this._id;
return arguments.length ? this.each(easeConstant(id, value)) : get(this.node(), id).ease;
}
//#endregion
//#region node_modules/d3-transition/src/transition/easeVarying.js
function easeVarying(id, value) {
return function() {
var v = value.apply(this, arguments);
if (typeof v !== "function") throw new Error();
set(this, id).ease = v;
};
}
function easeVarying_default(value) {
if (typeof value !== "function") throw new Error();
return this.each(easeVarying(this._id, value));
}
//#endregion
//#region node_modules/d3-transition/src/transition/filter.js
function filter_default(match) {
if (typeof match !== "function") match = matcher_default(match);
for (var groups = this._groups, m = groups.length, subgroups = new Array(m), j = 0; j < m; ++j) for (var group = groups[j], n = group.length, subgroup = subgroups[j] = [], node, i = 0; i < n; ++i) if ((node = group[i]) && match.call(node, node.__data__, i, group)) subgroup.push(node);
return new Transition(subgroups, this._parents, this._name, this._id);
}
//#endregion
//#region node_modules/d3-transition/src/transition/merge.js
function merge_default(transition) {
if (transition._id !== this._id) throw new Error();
for (var groups0 = this._groups, groups1 = transition._groups, m0 = groups0.length, m1 = groups1.length, m = Math.min(m0, m1), merges = new Array(m0), j = 0; j < m; ++j) for (var group0 = groups0[j], group1 = groups1[j], n = group0.length, merge = merges[j] = new Array(n), node, i = 0; i < n; ++i) if (node = group0[i] || group1[i]) merge[i] = node;
for (; j < m0; ++j) merges[j] = groups0[j];
return new Transition(merges, this._parents, this._name, this._id);
}
//#endregion
//#region node_modules/d3-transition/src/transition/on.js
function start(name) {
return (name + "").trim().split(/^|\s+/).every(function(t) {
var i = t.indexOf(".");
if (i >= 0) t = t.slice(0, i);
return !t || t === "start";
});
}
function onFunction(id, name, listener) {
var on0, on1, sit = start(name) ? init : set;
return function() {
var schedule = sit(this, id), on = schedule.on;
if (on !== on0) (on1 = (on0 = on).copy()).on(name, listener);
schedule.on = on1;
};
}
function on_default(name, listener) {
var id = this._id;
return arguments.length < 2 ? get(this.node(), id).on.on(name) : this.each(onFunction(id, name, listener));
}
//#endregion
//#region node_modules/d3-transition/src/transition/remove.js
function removeFunction(id) {
return function() {
var parent = this.parentNode;
for (var i in this.__transition) if (+i !== id) return;
if (parent) parent.removeChild(this);
};
}
function remove_default() {
return this.on("end.remove", removeFunction(this._id));
}
//#endregion
//#region node_modules/d3-transition/src/transition/select.js
function select_default(select) {
var name = this._name, id = this._id;
if (typeof select !== "function") select = selector_default(select);
for (var groups = this._groups, m = groups.length, subgroups = new Array(m), j = 0; j < m; ++j) for (var group = groups[j], n = group.length, subgroup = subgroups[j] = new Array(n), node, subnode, i = 0; i < n; ++i) if ((node = group[i]) && (subnode = select.call(node, node.__data__, i, group))) {
if ("__data__" in node) subnode.__data__ = node.__data__;
subgroup[i] = subnode;
schedule_default(subgroup[i], name, id, i, subgroup, get(node, id));
}
return new Transition(subgroups, this._parents, name, id);
}
//#endregion
//#region node_modules/d3-transition/src/transition/selectAll.js
function selectAll_default(select) {
var name = this._name, id = this._id;
if (typeof select !== "function") select = selectorAll_default(select);
for (var groups = this._groups, m = groups.length, subgroups = [], parents = [], j = 0; j < m; ++j) for (var group = groups[j], n = group.length, node, i = 0; i < n; ++i) if (node = group[i]) {
for (var children = select.call(node, node.__data__, i, group), child, inherit = get(node, id), k = 0, l = children.length; k < l; ++k) if (child = children[k]) schedule_default(child, name, id, k, children, inherit);
subgroups.push(children);
parents.push(node);
}
return new Transition(subgroups, parents, name, id);
}
//#endregion
//#region node_modules/d3-transition/src/transition/selection.js
var Selection = selection.prototype.constructor;
function selection_default() {
return new Selection(this._groups, this._parents);
}
//#endregion
//#region node_modules/d3-transition/src/transition/style.js
function styleNull(name, interpolate) {
var string00, string10, interpolate0;
return function() {
var string0 = styleValue(this, name), string1 = (this.style.removeProperty(name), styleValue(this, name));
return string0 === string1 ? null : string0 === string00 && string1 === string10 ? interpolate0 : interpolate0 = interpolate(string00 = string0, string10 = string1);
};
}
function styleRemove(name) {
return function() {
this.style.removeProperty(name);
};
}
function styleConstant(name, interpolate, value1) {
var string00, string1 = value1 + "", interpolate0;
return function() {
var string0 = styleValue(this, name);
return string0 === string1 ? null : string0 === string00 ? interpolate0 : interpolate0 = interpolate(string00 = string0, value1);
};
}
function styleFunction(name, interpolate, value) {
var string00, string10, interpolate0;
return function() {
var string0 = styleValue(this, name), value1 = value(this), string1 = value1 + "";
if (value1 == null) string1 = value1 = (this.style.removeProperty(name), styleValue(this, name));
return string0 === string1 ? null : string0 === string00 && string1 === string10 ? interpolate0 : (string10 = string1, interpolate0 = interpolate(string00 = string0, value1));
};
}
function styleMaybeRemove(id, name) {
var on0, on1, listener0, key = "style." + name, event = "end." + key, remove;
return function() {
var schedule = set(this, id), on = schedule.on, listener = schedule.value[key] == null ? remove || (remove = styleRemove(name)) : void 0;
if (on !== on0 || listener0 !== listener) (on1 = (on0 = on).copy()).on(event, listener0 = listener);
schedule.on = on1;
};
}
function style_default(name, value, priority) {
var i = (name += "") === "transform" ? interpolateTransformCss : interpolate_default;
return value == null ? this.styleTween(name, styleNull(name, i)).on("end.style." + name, styleRemove(name)) : typeof value === "function" ? this.styleTween(name, styleFunction(name, i, tweenValue(this, "style." + name, value))).each(styleMaybeRemove(this._id, name)) : this.styleTween(name, styleConstant(name, i, value), priority).on("end.style." + name, null);
}
//#endregion
//#region node_modules/d3-transition/src/transition/styleTween.js
function styleInterpolate(name, i, priority) {
return function(t) {
this.style.setProperty(name, i.call(this, t), priority);
};
}
function styleTween(name, value, priority) {
var t, i0;
function tween() {
var i = value.apply(this, arguments);
if (i !== i0) t = (i0 = i) && styleInterpolate(name, i, priority);
return t;
}
tween._value = value;
return tween;
}
function styleTween_default(name, value, priority) {
var key = "style." + (name += "");
if (arguments.length < 2) return (key = this.tween(key)) && key._value;
if (value == null) return this.tween(key, null);
if (typeof value !== "function") throw new Error();
return this.tween(key, styleTween(name, value, priority == null ? "" : priority));
}
//#endregion
//#region node_modules/d3-transition/src/transition/text.js
function textConstant(value) {
return function() {
this.textContent = value;
};
}
function textFunction(value) {
return function() {
var value1 = value(this);
this.textContent = value1 == null ? "" : value1;
};
}
function text_default(value) {
return this.tween("text", typeof value === "function" ? textFunction(tweenValue(this, "text", value)) : textConstant(value == null ? "" : value + ""));
}
//#endregion
//#region node_modules/d3-transition/src/transition/textTween.js
function textInterpolate(i) {
return function(t) {
this.textContent = i.call(this, t);
};
}
function textTween(value) {
var t0, i0;
function tween() {
var i = value.apply(this, arguments);
if (i !== i0) t0 = (i0 = i) && textInterpolate(i);
return t0;
}
tween._value = value;
return tween;
}
function textTween_default(value) {
var key = "text";
if (arguments.length < 1) return (key = this.tween(key)) && key._value;
if (value == null) return this.tween(key, null);
if (typeof value !== "function") throw new Error();
return this.tween(key, textTween(value));
}
//#endregion
//#region node_modules/d3-transition/src/transition/transition.js
function transition_default$1() {
var name = this._name, id0 = this._id, id1 = newId();
for (var groups = this._groups, m = groups.length, j = 0; j < m; ++j) for (var group = groups[j], n = group.length, node, i = 0; i < n; ++i) if (node = group[i]) {
var inherit = get(node, id0);
schedule_default(node, name, id1, i, group, {
time: inherit.time + inherit.delay + inherit.duration,
delay: 0,
duration: inherit.duration,
ease: inherit.ease
});
}
return new Transition(groups, this._parents, name, id1);
}
//#endregion
//#region node_modules/d3-transition/src/transition/end.js
function end_default() {
var on0, on1, that = this, id = that._id, size = that.size();
return new Promise(function(resolve, reject) {
var cancel = { value: reject }, end = { value: function() {
if (--size === 0) resolve();
} };
that.each(function() {
var schedule = set(this, id), on = schedule.on;
if (on !== on0) {
on1 = (on0 = on).copy();
on1._.cancel.push(cancel);
on1._.interrupt.push(cancel);
on1._.end.push(end);
}
schedule.on = on1;
});
if (size === 0) resolve();
});
}
//#endregion
//#region node_modules/d3-transition/src/transition/index.js
var id = 0;
function Transition(groups, parents, name, id) {
this._groups = groups;
this._parents = parents;
this._name = name;
this._id = id;
}
function transition(name) {
return selection().transition(name);
}
function newId() {
return ++id;
}
var selection_prototype = selection.prototype;
Transition.prototype = transition.prototype = {
constructor: Transition,
select: select_default,
selectAll: selectAll_default,
selectChild: selection_prototype.selectChild,
selectChildren: selection_prototype.selectChildren,
filter: filter_default,
merge: merge_default,
selection: selection_default,
transition: transition_default$1,
call: selection_prototype.call,
nodes: selection_prototype.nodes,
node: selection_prototype.node,
size: selection_prototype.size,
empty: selection_prototype.empty,
each: selection_prototype.each,
on: on_default,
attr: attr_default,
attrTween: attrTween_default,
style: style_default,
styleTween: styleTween_default,
text: text_default,
textTween: textTween_default,
remove: remove_default,
tween: tween_default,
delay: delay_default,
duration: duration_default,
ease: ease_default,
easeVarying: easeVarying_default,
end: end_default,
[Symbol.iterator]: selection_prototype[Symbol.iterator]
};
//#endregion
//#region node_modules/d3-ease/src/cubic.js
function cubicInOut(t) {
return ((t *= 2) <= 1 ? t * t * t : (t -= 2) * t * t + 2) / 2;
}
//#endregion
//#region node_modules/d3-transition/src/selection/transition.js
var defaultTiming = {
time: null,
delay: 0,
duration: 250,
ease: cubicInOut
};
function inherit(node, id) {
var timing;
while (!(timing = node.__transition) || !(timing = timing[id])) if (!(node = node.parentNode)) throw new Error(`transition ${id} not found`);
return timing;
}
function transition_default(name) {
var id, timing;
if (name instanceof Transition) id = name._id, name = name._name;
else id = newId(), (timing = defaultTiming).time = now(), name = name == null ? null : name + "";
for (var groups = this._groups, m = groups.length, j = 0; j < m; ++j) for (var group = groups[j], n = group.length, node, i = 0; i < n; ++i) if (node = group[i]) schedule_default(node, name, id, i, group, timing || inherit(node, id));
return new Transition(groups, this._parents, name, id);
}
//#endregion
//#region node_modules/d3-transition/src/selection/index.js
selection.prototype.interrupt = interrupt_default;
selection.prototype.transition = transition_default;
//#endregion
//#region node_modules/d3-zoom/src/constant.js
var constant_default = (x) => () => x;
//#endregion
//#region node_modules/d3-zoom/src/event.js
function ZoomEvent(type, { sourceEvent, target, transform, dispatch }) {
Object.defineProperties(this, {
type: {
value: type,
enumerable: true,
configurable: true
},
sourceEvent: {
value: sourceEvent,
enumerable: true,
configurable: true
},
target: {
value: target,
enumerable: true,
configurable: true
},
transform: {
value: transform,
enumerable: true,
configurable: true
},
_: { value: dispatch }
});
}
//#endregion
//#region node_modules/d3-zoom/src/transform.js
function Transform(k, x, y) {
this.k = k;
this.x = x;
this.y = y;
}
Transform.prototype = {
constructor: Transform,
scale: function(k) {
return k === 1 ? this : new Transform(this.k * k, this.x, this.y);
},
translate: function(x, y) {
return x === 0 & y === 0 ? this : new Transform(this.k, this.x + this.k * x, this.y + this.k * y);
},
apply: function(point) {
return [point[0] * this.k + this.x, point[1] * this.k + this.y];
},
applyX: function(x) {
return x * this.k + this.x;
},
applyY: function(y) {
return y * this.k + this.y;
},
invert: function(location) {
return [(location[0] - this.x) / this.k, (location[1] - this.y) / this.k];
},
invertX: function(x) {
return (x - this.x) / this.k;
},
invertY: function(y) {
return (y - this.y) / this.k;
},
rescaleX: function(x) {
return x.copy().domain(x.range().map(this.invertX, this).map(x.invert, x));
},
rescaleY: function(y) {
return y.copy().domain(y.range().map(this.invertY, this).map(y.invert, y));
},
toString: function() {
return "translate(" + this.x + "," + this.y + ") scale(" + this.k + ")";
}
};
var identity$1 = new Transform(1, 0, 0);
transform.prototype = Transform.prototype;
function transform(node) {
while (!node.__zoom) if (!(node = node.parentNode)) return identity$1;
return node.__zoom;
}
//#endregion
//#region node_modules/d3-zoom/src/noevent.js
function nopropagation(event) {
event.stopImmediatePropagation();
}
function noevent_default(event) {
event.preventDefault();
event.stopImmediatePropagation();
}
//#endregion
//#region node_modules/d3-zoom/src/zoom.js
function defaultFilter(event) {
return (!event.ctrlKey || event.type === "wheel") && !event.button;
}
function defaultExtent() {
var e = this;
if (e instanceof SVGElement) {
e = e.ownerSVGElement || e;
if (e.hasAttribute("viewBox")) {
e = e.viewBox.baseVal;
return [[e.x, e.y], [e.x + e.width, e.y + e.height]];
}
return [[0, 0], [e.width.baseVal.value, e.height.baseVal.value]];
}
return [[0, 0], [e.clientWidth, e.clientHeight]];
}
function defaultTransform() {
return this.__zoom || identity$1;
}
function defaultWheelDelta(event) {
return -event.deltaY * (event.deltaMode === 1 ? .05 : event.deltaMode ? 1 : .002) * (event.ctrlKey ? 10 : 1);
}
function defaultTouchable() {
return navigator.maxTouchPoints || "ontouchstart" in this;
}
function defaultConstrain(transform, extent, translateExtent) {
var dx0 = transform.invertX(extent[0][0]) - translateExtent[0][0], dx1 = transform.invertX(extent[1][0]) - translateExtent[1][0], dy0 = transform.invertY(extent[0][1]) - translateExtent[0][1], dy1 = transform.invertY(extent[1][1]) - translateExtent[1][1];
return transform.translate(dx1 > dx0 ? (dx0 + dx1) / 2 : Math.min(0, dx0) || Math.max(0, dx1), dy1 > dy0 ? (dy0 + dy1) / 2 : Math.min(0, dy0) || Math.max(0, dy1));
}
function zoom_default() {
var filter = defaultFilter, extent = defaultExtent, constrain = defaultConstrain, wheelDelta = defaultWheelDelta, touchable = defaultTouchable, scaleExtent = [0, Infinity], translateExtent = [[-Infinity, -Infinity], [Infinity, Infinity]], duration = 250, interpolate = zoom_default$1, listeners = dispatch("start", "zoom", "end"), touchstarting, touchfirst, touchending, touchDelay = 500, wheelDelay = 150, clickDistance2 = 0, tapDistance = 10;
function zoom(selection) {
selection.property("__zoom", defaultTransform).on("wheel.zoom", wheeled, { passive: false }).on("mousedown.zoom", mousedowned).on("dblclick.zoom", dblclicked).filter(touchable).on("touchstart.zoom", touchstarted).on("touchmove.zoom", touchmoved).on("touchend.zoom touchcancel.zoom", touchended).style("-webkit-tap-highlight-color", "rgba(0,0,0,0)");
}
zoom.transform = function(collection, transform, point, event) {
var selection = collection.selection ? collection.selection() : collection;
selection.property("__zoom", defaultTransform);
if (collection !== selection) schedule(collection, transform, point, event);
else selection.interrupt().each(function() {
gesture(this, arguments).event(event).start().zoom(null, typeof transform === "function" ? transform.apply(this, arguments) : transform).end();
});
};
zoom.scaleBy = function(selection, k, p, event) {
zoom.scaleTo(selection, function() {
return this.__zoom.k * (typeof k === "function" ? k.apply(this, arguments) : k);
}, p, event);
};
zoom.scaleTo = function(selection, k, p, event) {
zoom.transform(selection, function() {
var e = extent.apply(this, arguments), t0 = this.__zoom, p0 = p == null ? centroid(e) : typeof p === "function" ? p.apply(this, arguments) : p, p1 = t0.invert(p0), k1 = typeof k === "function" ? k.apply(this, arguments) : k;
return constrain(translate(scale(t0, k1), p0, p1), e, translateExtent);
}, p, event);
};
zoom.translateBy = function(selection, x, y, event) {
zoom.transform(selection, function() {
return constrain(this.__zoom.translate(typeof x === "function" ? x.apply(this, arguments) : x, typeof y === "function" ? y.apply(this, arguments) : y), extent.apply(this, arguments), translateExtent);
}, null, event);
};
zoom.translateTo = function(selection, x, y, p, event) {
zoom.transform(selection, function() {
var e = extent.apply(this, arguments), t = this.__zoom, p0 = p == null ? centroid(e) : typeof p === "function" ? p.apply(this, arguments) : p;
return constrain(identity$1.translate(p0[0], p0[1]).scale(t.k).translate(typeof x === "function" ? -x.apply(this, arguments) : -x, typeof y === "function" ? -y.apply(this, arguments) : -y), e, translateExtent);
}, p, event);
};
function scale(transform, k) {
k = Math.max(scaleExtent[0], Math.min(scaleExtent[1], k));
return k === transform.k ? transform : new Transform(k, transform.x, transform.y);
}
function translate(transform, p0, p1) {
var x = p0[0] - p1[0] * transform.k, y = p0[1] - p1[1] * transform.k;
return x === transform.x && y === transform.y ? transform : new Transform(transform.k, x, y);
}
function centroid(extent) {
return [(+extent[0][0] + +extent[1][0]) / 2, (+extent[0][1] + +extent[1][1]) / 2];
}
function schedule(transition, transform, point, event) {
transition.on("start.zoom", function() {
gesture(this, arguments).event(event).start();
}).on("interrupt.zoom end.zoom", function() {
gesture(this, arguments).event(event).end();
}).tween("zoom", function() {
var that = this, args = arguments, g = gesture(that, args).event(event), e = extent.apply(that, args), p = point == null ? centroid(e) : typeof point === "function" ? point.apply(that, args) : point, w = Math.max(e[1][0] - e[0][0], e[1][1] - e[0][1]), a = that.__zoom, b = typeof transform === "function" ? transform.apply(that, args) : transform, i = interpolate(a.invert(p).concat(w / a.k), b.invert(p).concat(w / b.k));
return function(t) {
if (t === 1) t = b;
else {
var l = i(t), k = w / l[2];
t = new Transform(k, p[0] - l[0] * k, p[1] - l[1] * k);
}
g.zoom(null, t);
};
});
}
function gesture(that, args, clean) {
return !clean && that.__zooming || new Gesture(that, args);
}
function Gesture(that, args) {
this.that = that;
this.args = args;
this.active = 0;
this.sourceEvent = null;
this.extent = extent.apply(that, args);
this.taps = 0;
}
Gesture.prototype = {
event: function(event) {
if (event) this.sourceEvent = event;
return this;
},
start: function() {
if (++this.active === 1) {
this.that.__zooming = this;
this.emit("start");
}
return this;
},
zoom: function(key, transform) {
if (this.mouse && key !== "mouse") this.mouse[1] = transform.invert(this.mouse[0]);
if (this.touch0 && key !== "touch") this.touch0[1] = transform.invert(this.touch0[0]);
if (this.touch1 && key !== "touch") this.touch1[1] = transform.invert(this.touch1[0]);
this.that.__zoom = transform;
this.emit("zoom");
return this;
},
end: function() {
if (--this.active === 0) {
delete this.that.__zooming;
this.emit("end");
}
return this;
},
emit: function(type) {
var d = select_default$1(this.that).datum();
listeners.call(type, this.that, new ZoomEvent(type, {
sourceEvent: this.sourceEvent,
target: zoom,
type,
transform: this.that.__zoom,
dispatch: listeners
}), d);
}
};
function wheeled(event, ...args) {
if (!filter.apply(this, arguments)) return;
var g = gesture(this, args).event(event), t = this.__zoom, k = Math.max(scaleExtent[0], Math.min(scaleExtent[1], t.k * Math.pow(2, wheelDelta.apply(this, arguments)))), p = pointer_default(event);
if (g.wheel) {
if (g.mouse[0][0] !== p[0] || g.mouse[0][1] !== p[1]) g.mouse[1] = t.invert(g.mouse[0] = p);
clearTimeout(g.wheel);
} else if (t.k === k) return;
else {
g.mouse = [p, t.invert(p)];
interrupt_default$1(this);
g.start();
}
noevent_default(event);
g.wheel = setTimeout(wheelidled, wheelDelay);
g.zoom("mouse", constrain(translate(scale(t, k), g.mouse[0], g.mouse[1]), g.extent, translateExtent));
function wheelidled() {
g.wheel = null;
g.end();
}
}
function mousedowned(event, ...args) {
if (touchending || !filter.apply(this, arguments)) return;
var currentTarget = event.currentTarget, g = gesture(this, args, true).event(event), v = select_default$1(event.view).on("mousemove.zoom", mousemoved, true).on("mouseup.zoom", mouseupped, true), p = pointer_default(event, currentTarget), x0 = event.clientX, y0 = event.clientY;
nodrag_default(event.view);
nopropagation(event);
g.mouse = [p, this.__zoom.invert(p)];
interrupt_default$1(this);
g.start();
function mousemoved(event) {
noevent_default(event);
if (!g.moved) {
var dx = event.clientX - x0, dy = event.clientY - y0;
g.moved = dx * dx + dy * dy > clickDistance2;
}
g.event(event).zoom("mouse", constrain(translate(g.that.__zoom, g.mouse[0] = pointer_default(event, currentTarget), g.mouse[1]), g.extent, translateExtent));
}
function mouseupped(event) {
v.on("mousemove.zoom mouseup.zoom", null);
yesdrag(event.view, g.moved);
noevent_default(event);
g.event(event).end();
}
}
function dblclicked(event, ...args) {
if (!filter.apply(this, arguments)) return;
var t0 = this.__zoom, p0 = pointer_default(event.changedTouches ? event.changedTouches[0] : event, this), p1 = t0.invert(p0), k1 = t0.k * (event.shiftKey ? .5 : 2), t1 = constrain(translate(scale(t0, k1), p0, p1), extent.apply(this, args), translateExtent);
noevent_default(event);
if (duration > 0) select_default$1(this).transition().duration(duration).call(schedule, t1, p0, event);
else select_default$1(this).call(zoom.transform, t1, p0, event);
}
function touchstarted(event, ...args) {
if (!filter.apply(this, arguments)) return;
var touches = event.touches, n = touches.length, g = gesture(this, args, event.changedTouches.length === n).event(event), started, i, t, p;
nopropagation(event);
for (i = 0; i < n; ++i) {
t = touches[i], p = pointer_default(t, this);
p = [
p,
this.__zoom.invert(p),
t.identifier
];
if (!g.touch0) g.touch0 = p, started = true, g.taps = 1 + !!touchstarting;
else if (!g.touch1 && g.touch0[2] !== p[2]) g.touch1 = p, g.taps = 0;
}
if (touchstarting) touchstarting = clearTimeout(touchstarting);
if (started) {
if (g.taps < 2) touchfirst = p[0], touchstarting = setTimeout(function() {
touchstarting = null;
}, touchDelay);
interrupt_default$1(this);
g.start();
}
}
function touchmoved(event, ...args) {
if (!this.__zooming) return;
var g = gesture(this, args).event(event), touches = event.changedTouches, n = touches.length, i, t, p, l;
noevent_default(event);
for (i = 0; i < n; ++i) {
t = touches[i], p = pointer_default(t, this);
if (g.touch0 && g.touch0[2] === t.identifier) g.touch0[0] = p;
else if (g.touch1 && g.touch1[2] === t.identifier) g.touch1[0] = p;
}
t = g.that.__zoom;
if (g.touch1) {
var p0 = g.touch0[0], l0 = g.touch0[1], p1 = g.touch1[0], l1 = g.touch1[1], dp = (dp = p1[0] - p0[0]) * dp + (dp = p1[1] - p0[1]) * dp, dl = (dl = l1[0] - l0[0]) * dl + (dl = l1[1] - l0[1]) * dl;
t = scale(t, Math.sqrt(dp / dl));
p = [(p0[0] + p1[0]) / 2, (p0[1] + p1[1]) / 2];
l = [(l0[0] + l1[0]) / 2, (l0[1] + l1[1]) / 2];
} else if (g.touch0) p = g.touch0[0], l = g.touch0[1];
else return;
g.zoom("touch", constrain(translate(t, p, l), g.extent, translateExtent));
}
function touchended(event, ...args) {
if (!this.__zooming) return;
var g = gesture(this, args).event(event), touches = event.changedTouches, n = touches.length, i, t;
nopropagation(event);
if (touchending) clearTimeout(touchending);
touchending = setTimeout(function() {
touchending = null;
}, touchDelay);
for (i = 0; i < n; ++i) {
t = touches[i];
if (g.touch0 && g.touch0[2] === t.identifier) delete g.touch0;
else if (g.touch1 && g.touch1[2] === t.identifier) delete g.touch1;
}
if (g.touch1 && !g.touch0) g.touch0 = g.touch1, delete g.touch1;
if (g.touch0) g.touch0[1] = this.__zoom.invert(g.touch0[0]);
else {
g.end();
if (g.taps === 2) {
t = pointer_default(t, this);
if (Math.hypot(touchfirst[0] - t[0], touchfirst[1] - t[1]) < tapDistance) {
var p = select_default$1(this).on("dblclick.zoom");
if (p) p.apply(this, arguments);
}
}
}
}
zoom.wheelDelta = function(_) {
return arguments.length ? (wheelDelta = typeof _ === "function" ? _ : constant_default(+_), zoom) : wheelDelta;
};
zoom.filter = function(_) {
return arguments.length ? (filter = typeof _ === "function" ? _ : constant_default(!!_), zoom) : filter;
};
zoom.touchable = function(_) {
return arguments.length ? (touchable = typeof _ === "function" ? _ : constant_default(!!_), zoom) : touchable;
};
zoom.extent = function(_) {
return arguments.length ? (extent = typeof _ === "function" ? _ : constant_default([[+_[0][0], +_[0][1]], [+_[1][0], +_[1][1]]]), zoom) : extent;
};
zoom.scaleExtent = function(_) {
return arguments.length ? (scaleExtent[0] = +_[0], scaleExtent[1] = +_[1], zoom) : [scaleExtent[0], scaleExtent[1]];
};
zoom.translateExtent = function(_) {
return arguments.length ? (translateExtent[0][0] = +_[0][0], translateExtent[1][0] = +_[1][0], translateExtent[0][1] = +_[0][1], translateExtent[1][1] = +_[1][1], zoom) : [[translateExtent[0][0], translateExtent[0][1]], [translateExtent[1][0], translateExtent[1][1]]];
};
zoom.constrain = function(_) {
return arguments.length ? (constrain = _, zoom) : constrain;
};
zoom.duration = function(_) {
return arguments.length ? (duration = +_, zoom) : duration;
};
zoom.interpolate = function(_) {
return arguments.length ? (interpolate = _, zoom) : interpolate;
};
zoom.on = function() {
var value = listeners.on.apply(listeners, arguments);
return value === listeners ? zoom : value;
};
zoom.clickDistance = function(_) {
return arguments.length ? (clickDistance2 = (_ = +_) * _, zoom) : Math.sqrt(clickDistance2);
};
zoom.tapDistance = function(_) {
return arguments.length ? (tapDistance = +_, zoom) : tapDistance;
};
return zoom;
}
//#endregion
//#region node_modules/@xyflow/system/dist/esm/index.js
var errorMessages = {
error001: (lib = "react") => `Seems like you have not used zustand provider as an ancestor. Help: https://${lib}flow.dev/error#001`,
error002: () => "It looks like you've created a new nodeTypes or edgeTypes object. If this wasn't on purpose please define the nodeTypes/edgeTypes outside of the component or memoize them.",
error003: (nodeType) => `Node type "${nodeType}" not found. Using fallback type "default".`,
error004: () => "The parent container needs a width and a height to render the graph.",
error005: () => "Only child nodes can use a parent extent.",
error006: () => "Can't create edge. An edge needs a source and a target.",
error007: (id) => `The old edge with id=${id} does not exist.`,
error009: (type) => `Marker type "${type}" doesn't exist.`,
error008: (handleType, { id, sourceHandle, targetHandle }) => `Couldn't create edge for ${handleType} handle id: "${handleType === "source" ? sourceHandle : targetHandle}", edge id: ${id}.`,
error010: () => "Handle: No node id found. Make sure to only use a Handle inside a custom Node.",
error011: (edgeType) => `Edge type "${edgeType}" not found. Using fallback type "default".`,
error012: (id) => `Node with id "${id}" does not exist, it may have been removed. This can happen when a node is deleted before the "onNodeClick" handler is called.`,
error013: (lib = "react") => `It seems that you haven't loaded the styles. Please import '@xyflow/${lib}/dist/style.css' or base.css to make sure everything is working properly.`,
error014: () => "useNodeConnections: No node ID found. Call useNodeConnections inside a custom Node or provide a node ID.",
error015: () => "It seems that you are trying to drag a node that is not initialized. Please use onNodesChange as explained in the docs.",
error016: (id) => `Edge with id "${id}" does not exist, it may have been removed. This can happen when an edge is deleted before the "onEdgeClick" handler is called.`
};
var infiniteExtent = [[Number.NEGATIVE_INFINITY, Number.NEGATIVE_INFINITY], [Number.POSITIVE_INFINITY, Number.POSITIVE_INFINITY]];
var elementSelectionKeys = [
"Enter",
" ",
"Escape"
];
var defaultAriaLabelConfig = {
"node.a11yDescription.default": "Press enter or space to select a node. Press delete to remove it and escape to cancel.",
"node.a11yDescription.keyboardDisabled": "Press enter or space to select a node. You can then use the arrow keys to move the node around. Press delete to remove it and escape to cancel.",
"node.a11yDescription.ariaLiveMessage": ({ direction, x, y }) => `Moved selected node ${direction}. New position, x: ${x}, y: ${y}`,
"edge.a11yDescription.default": "Press enter or space to select an edge. You can then press delete to remove it or escape to cancel.",
"controls.ariaLabel": "Control Panel",
"controls.zoomIn.ariaLabel": "Zoom In",
"controls.zoomOut.ariaLabel": "Zoom Out",
"controls.fitView.ariaLabel": "Fit View",
"controls.interactive.ariaLabel": "Toggle Interactivity",
"minimap.ariaLabel": "Mini Map",
"handle.ariaLabel": "Handle"
};
/**
* The `ConnectionMode` is used to set the mode of connection between nodes.
* The `Strict` mode is the default one and only allows source to target edges.
* `Loose` mode allows source to source and target to target edges as well.
*
* @public
*/
var ConnectionMode;
(function(ConnectionMode) {
ConnectionMode["Strict"] = "strict";
ConnectionMode["Loose"] = "loose";
})(ConnectionMode || (ConnectionMode = {}));
/**
* This enum is used to set the different modes of panning the viewport when the
* user scrolls. The `Free` mode allows the user to pan in any direction by scrolling
* with a device like a trackpad. The `Vertical` and `Horizontal` modes restrict
* scroll panning to only the vertical or horizontal axis, respectively.
*
* @public
*/
var PanOnScrollMode;
(function(PanOnScrollMode) {
PanOnScrollMode["Free"] = "free";
PanOnScrollMode["Vertical"] = "vertical";
PanOnScrollMode["Horizontal"] = "horizontal";
})(PanOnScrollMode || (PanOnScrollMode = {}));
var SelectionMode;
(function(SelectionMode) {
SelectionMode["Partial"] = "partial";
SelectionMode["Full"] = "full";
})(SelectionMode || (SelectionMode = {}));
var initialConnection = {
inProgress: false,
isValid: null,
from: null,
fromHandle: null,
fromPosition: null,
fromNode: null,
to: null,
toHandle: null,
toPosition: null,
toNode: null,
pointer: null
};
/**
* If you set the `connectionLineType` prop on your [``](/api-reference/react-flow#connection-connectionLineType)
*component, it will dictate the style of connection line rendered when creating
*new edges.
*
* @public
*
* @remarks If you choose to render a custom connection line component, this value will be
*passed to your component as part of its [`ConnectionLineComponentProps`](/api-reference/types/connection-line-component-props).
*/
var ConnectionLineType;
(function(ConnectionLineType) {
ConnectionLineType["Bezier"] = "default";
ConnectionLineType["Straight"] = "straight";
ConnectionLineType["Step"] = "step";
ConnectionLineType["SmoothStep"] = "smoothstep";
ConnectionLineType["SimpleBezier"] = "simplebezier";
})(ConnectionLineType || (ConnectionLineType = {}));
/**
* Edges may optionally have a marker on either end. The MarkerType type enumerates
* the options available to you when configuring a given marker.
*
* @public
*/
var MarkerType;
(function(MarkerType) {
MarkerType["Arrow"] = "arrow";
MarkerType["ArrowClosed"] = "arrowclosed";
})(MarkerType || (MarkerType = {}));
/**
* While [`PanelPosition`](/api-reference/types/panel-position) can be used to place a
* component in the corners of a container, the `Position` enum is less precise and used
* primarily in relation to edges and handles.
*
* @public
*/
var Position;
(function(Position) {
Position["Left"] = "left";
Position["Top"] = "top";
Position["Right"] = "right";
Position["Bottom"] = "bottom";
})(Position || (Position = {}));
var oppositePosition = {
[Position.Left]: Position.Right,
[Position.Right]: Position.Left,
[Position.Top]: Position.Bottom,
[Position.Bottom]: Position.Top
};
/**
* @internal
*/
function areConnectionMapsEqual(a, b) {
if (!a && !b) return true;
if (!a || !b || a.size !== b.size) return false;
if (!a.size && !b.size) return true;
for (const key of a.keys()) if (!b.has(key)) return false;
return true;
}
/**
* We call the callback for all connections in a that are not in b
*
* @internal
*/
function handleConnectionChange(a, b, cb) {
if (!cb) return;
const diff = [];
a.forEach((connection, key) => {
if (!b?.has(key)) diff.push(connection);
});
if (diff.length) cb(diff);
}
function getConnectionStatus(isValid) {
return isValid === null ? null : isValid ? "valid" : "invalid";
}
/**
* Test whether an object is usable as an Edge
* @public
* @remarks In TypeScript this is a type guard that will narrow the type of whatever you pass in to Edge if it returns true
* @param element - The element to test
* @returns A boolean indicating whether the element is an Edge
*/
var isEdgeBase = (element) => "id" in element && "source" in element && "target" in element;
/**
* Test whether an object is usable as a Node
* @public
* @remarks In TypeScript this is a type guard that will narrow the type of whatever you pass in to Node if it returns true
* @param element - The element to test
* @returns A boolean indicating whether the element is an Node
*/
var isNodeBase = (element) => "id" in element && "position" in element && !("source" in element) && !("target" in element);
var isInternalNodeBase = (element) => "id" in element && "internals" in element && !("source" in element) && !("target" in element);
/**
* This util is used to tell you what nodes, if any, are connected to the given node
* as the _target_ of an edge.
* @public
* @param node - The node to get the connected nodes from.
* @param nodes - The array of all nodes.
* @param edges - The array of all edges.
* @returns An array of nodes that are connected over edges where the source is the given node.
*
* @example
* ```ts
*import { getOutgoers } from '@xyflow/react';
*
*const nodes = [];
*const edges = [];
*
*const outgoers = getOutgoers(
* { id: '1', position: { x: 0, y: 0 }, data: { label: 'node' } },
* nodes,
* edges,
*);
*```
*/
var getOutgoers = (node, nodes, edges) => {
if (!node.id) return [];
const outgoerIds = /* @__PURE__ */ new Set();
edges.forEach((edge) => {
if (edge.source === node.id) outgoerIds.add(edge.target);
});
return nodes.filter((n) => outgoerIds.has(n.id));
};
/**
* This util is used to tell you what nodes, if any, are connected to the given node
* as the _source_ of an edge.
* @public
* @param node - The node to get the connected nodes from.
* @param nodes - The array of all nodes.
* @param edges - The array of all edges.
* @returns An array of nodes that are connected over edges where the target is the given node.
*
* @example
* ```ts
*import { getIncomers } from '@xyflow/react';
*
*const nodes = [];
*const edges = [];
*
*const incomers = getIncomers(
* { id: '1', position: { x: 0, y: 0 }, data: { label: 'node' } },
* nodes,
* edges,
*);
*```
*/
var getIncomers = (node, nodes, edges) => {
if (!node.id) return [];
const incomersIds = /* @__PURE__ */ new Set();
edges.forEach((edge) => {
if (edge.target === node.id) incomersIds.add(edge.source);
});
return nodes.filter((n) => incomersIds.has(n.id));
};
var getNodePositionWithOrigin = (node, nodeOrigin = [0, 0]) => {
const { width, height } = getNodeDimensions(node);
const origin = node.origin ?? nodeOrigin;
const offsetX = width * origin[0];
const offsetY = height * origin[1];
return {
x: node.position.x - offsetX,
y: node.position.y - offsetY
};
};
/**
* Returns the bounding box that contains all the given nodes in an array. This can
* be useful when combined with [`getViewportForBounds`](/api-reference/utils/get-viewport-for-bounds)
* to calculate the correct transform to fit the given nodes in a viewport.
* @public
* @remarks Useful when combined with {@link getViewportForBounds} to calculate the correct transform to fit the given nodes in a viewport.
* @param nodes - Nodes to calculate the bounds for.
* @returns Bounding box enclosing all nodes.
*
* @remarks This function was previously called `getRectOfNodes`
*
* @example
* ```js
*import { getNodesBounds } from '@xyflow/react';
*
*const nodes = [
* {
* id: 'a',
* position: { x: 0, y: 0 },
* data: { label: 'a' },
* width: 50,
* height: 25,
* },
* {
* id: 'b',
* position: { x: 100, y: 100 },
* data: { label: 'b' },
* width: 50,
* height: 25,
* },
*];
*
*const bounds = getNodesBounds(nodes);
*```
*/
var getNodesBounds = (nodes, params = { nodeOrigin: [0, 0] }) => {
if (!params.nodeLookup) console.warn("Please use `getNodesBounds` from `useReactFlow`/`useSvelteFlow` hook to ensure correct values for sub flows. If not possible, you have to provide a nodeLookup to support sub flows.");
if (nodes.length === 0) return {
x: 0,
y: 0,
width: 0,
height: 0
};
return boxToRect(nodes.reduce((currBox, nodeOrId) => {
const isId = typeof nodeOrId === "string";
let currentNode = !params.nodeLookup && !isId ? nodeOrId : void 0;
if (params.nodeLookup) currentNode = isId ? params.nodeLookup.get(nodeOrId) : !isInternalNodeBase(nodeOrId) ? params.nodeLookup.get(nodeOrId.id) : nodeOrId;
return getBoundsOfBoxes(currBox, currentNode ? nodeToBox(currentNode, params.nodeOrigin) : {
x: 0,
y: 0,
x2: 0,
y2: 0
});
}, {
x: Infinity,
y: Infinity,
x2: -Infinity,
y2: -Infinity
}));
};
/**
* Determines a bounding box that contains all given nodes in an array
* @internal
*/
var getInternalNodesBounds = (nodeLookup, params = {}) => {
let box = {
x: Infinity,
y: Infinity,
x2: -Infinity,
y2: -Infinity
};
let hasVisibleNodes = false;
nodeLookup.forEach((node) => {
if (params.filter === void 0 || params.filter(node)) {
box = getBoundsOfBoxes(box, nodeToBox(node));
hasVisibleNodes = true;
}
});
return hasVisibleNodes ? boxToRect(box) : {
x: 0,
y: 0,
width: 0,
height: 0
};
};
var getNodesInside = (nodes, rect, [tx, ty, tScale] = [
0,
0,
1
], partially = false, excludeNonSelectableNodes = false) => {
const paneRect = {
...pointToRendererPoint(rect, [
tx,
ty,
tScale
]),
width: rect.width / tScale,
height: rect.height / tScale
};
const visibleNodes = [];
for (const node of nodes.values()) {
const { measured, selectable = true, hidden = false } = node;
if (excludeNonSelectableNodes && !selectable || hidden) continue;
const width = measured.width ?? node.width ?? node.initialWidth ?? null;
const height = measured.height ?? node.height ?? node.initialHeight ?? null;
const overlappingArea = getOverlappingArea(paneRect, nodeToRect(node));
const area = (width ?? 0) * (height ?? 0);
const partiallyVisible = partially && overlappingArea > 0;
if (!node.internals.handleBounds || partiallyVisible || overlappingArea >= area || node.dragging) visibleNodes.push(node);
}
return visibleNodes;
};
/**
* This utility filters an array of edges, keeping only those where either the source or target
* node is present in the given array of nodes.
* @public
* @param nodes - Nodes you want to get the connected edges for.
* @param edges - All edges.
* @returns Array of edges that connect any of the given nodes with each other.
*
* @example
* ```js
*import { getConnectedEdges } from '@xyflow/react';
*
*const nodes = [
* { id: 'a', position: { x: 0, y: 0 } },
* { id: 'b', position: { x: 100, y: 0 } },
*];
*
*const edges = [
* { id: 'a->c', source: 'a', target: 'c' },
* { id: 'c->d', source: 'c', target: 'd' },
*];
*
*const connectedEdges = getConnectedEdges(nodes, edges);
* // => [{ id: 'a->c', source: 'a', target: 'c' }]
*```
*/
var getConnectedEdges = (nodes, edges) => {
const nodeIds = /* @__PURE__ */ new Set();
nodes.forEach((node) => {
nodeIds.add(node.id);
});
return edges.filter((edge) => nodeIds.has(edge.source) || nodeIds.has(edge.target));
};
function getFitViewNodes(nodeLookup, options) {
const fitViewNodes = /* @__PURE__ */ new Map();
const optionNodeIds = options?.nodes ? new Set(options.nodes.map((node) => node.id)) : null;
nodeLookup.forEach((n) => {
if (n.measured.width && n.measured.height && (options?.includeHiddenNodes || !n.hidden) && (!optionNodeIds || optionNodeIds.has(n.id))) fitViewNodes.set(n.id, n);
});
return fitViewNodes;
}
async function fitViewport({ nodes, width, height, panZoom, minZoom, maxZoom }, options) {
if (nodes.size === 0) return true;
const viewport = getViewportForBounds(getInternalNodesBounds(getFitViewNodes(nodes, options)), width, height, options?.minZoom ?? minZoom, options?.maxZoom ?? maxZoom, options?.padding ?? .1);
await panZoom.setViewport(viewport, {
duration: options?.duration,
ease: options?.ease,
interpolate: options?.interpolate
});
return true;
}
/**
* This function calculates the next position of a node, taking into account the node's extent, parent node, and origin.
*
* @internal
* @returns position, positionAbsolute
*/
function calculateNodePosition({ nodeId, nextPosition, nodeLookup, nodeOrigin = [0, 0], nodeExtent, onError }) {
const node = nodeLookup.get(nodeId);
const parentNode = node.parentId ? nodeLookup.get(node.parentId) : void 0;
const { x: parentX, y: parentY } = parentNode ? parentNode.internals.positionAbsolute : {
x: 0,
y: 0
};
const origin = node.origin ?? nodeOrigin;
let extent = node.extent || nodeExtent;
if (node.extent === "parent" && !node.expandParent) if (!parentNode) onError?.("005", errorMessages["error005"]());
else {
const parentWidth = parentNode.measured.width;
const parentHeight = parentNode.measured.height;
if (parentWidth && parentHeight) extent = [[parentX, parentY], [parentX + parentWidth, parentY + parentHeight]];
}
else if (parentNode && isCoordinateExtent(node.extent)) extent = [[node.extent[0][0] + parentX, node.extent[0][1] + parentY], [node.extent[1][0] + parentX, node.extent[1][1] + parentY]];
const positionAbsolute = isCoordinateExtent(extent) ? clampPosition(nextPosition, extent, node.measured) : nextPosition;
if (node.measured.width === void 0 || node.measured.height === void 0) onError?.("015", errorMessages["error015"]());
return {
position: {
x: positionAbsolute.x - parentX + (node.measured.width ?? 0) * origin[0],
y: positionAbsolute.y - parentY + (node.measured.height ?? 0) * origin[1]
},
positionAbsolute
};
}
/**
* Pass in nodes & edges to delete, get arrays of nodes and edges that actually can be deleted
* @internal
* @param param.nodesToRemove - The nodes to remove
* @param param.edgesToRemove - The edges to remove
* @param param.nodes - All nodes
* @param param.edges - All edges
* @param param.onBeforeDelete - Callback to check which nodes and edges can be deleted
* @returns nodes: nodes that can be deleted, edges: edges that can be deleted
*/
async function getElementsToRemove({ nodesToRemove = [], edgesToRemove = [], nodes, edges, onBeforeDelete }) {
const nodeIds = new Set(nodesToRemove.map((node) => node.id));
const matchingNodes = [];
for (const node of nodes) {
if (node.deletable === false) continue;
const isIncluded = nodeIds.has(node.id);
const parentHit = !isIncluded && node.parentId && matchingNodes.find((n) => n.id === node.parentId);
if (isIncluded || parentHit) matchingNodes.push(node);
}
const edgeIds = new Set(edgesToRemove.map((edge) => edge.id));
const deletableEdges = edges.filter((edge) => edge.deletable !== false);
const matchingEdges = getConnectedEdges(matchingNodes, deletableEdges);
for (const edge of deletableEdges) if (edgeIds.has(edge.id) && !matchingEdges.find((e) => e.id === edge.id)) matchingEdges.push(edge);
if (!onBeforeDelete) return {
edges: matchingEdges,
nodes: matchingNodes
};
const onBeforeDeleteResult = await onBeforeDelete({
nodes: matchingNodes,
edges: matchingEdges
});
if (typeof onBeforeDeleteResult === "boolean") return onBeforeDeleteResult ? {
edges: matchingEdges,
nodes: matchingNodes
} : {
edges: [],
nodes: []
};
return onBeforeDeleteResult;
}
var clamp = (val, min = 0, max = 1) => Math.min(Math.max(val, min), max);
var clampPosition = (position = {
x: 0,
y: 0
}, extent, dimensions) => ({
x: clamp(position.x, extent[0][0], extent[1][0] - (dimensions?.width ?? 0)),
y: clamp(position.y, extent[0][1], extent[1][1] - (dimensions?.height ?? 0))
});
function clampPositionToParent(childPosition, childDimensions, parent) {
const { width: parentWidth, height: parentHeight } = getNodeDimensions(parent);
const { x: parentX, y: parentY } = parent.internals.positionAbsolute;
return clampPosition(childPosition, [[parentX, parentY], [parentX + parentWidth, parentY + parentHeight]], childDimensions);
}
/**
* Calculates the velocity of panning when the mouse is close to the edge of the canvas
* @internal
* @param value - One dimensional poition of the mouse (x or y)
* @param min - Minimal position on canvas before panning starts
* @param max - Maximal position on canvas before panning starts
* @returns - A number between 0 and 1 that represents the velocity of panning
*/
var calcAutoPanVelocity = (value, min, max) => {
if (value < min) return clamp(Math.abs(value - min), 1, min) / min;
else if (value > max) return -clamp(Math.abs(value - max), 1, min) / min;
return 0;
};
var calcAutoPan = (pos, bounds, speed = 15, distance = 40) => {
return [calcAutoPanVelocity(pos.x, distance, bounds.width - distance) * speed, calcAutoPanVelocity(pos.y, distance, bounds.height - distance) * speed];
};
var getBoundsOfBoxes = (box1, box2) => ({
x: Math.min(box1.x, box2.x),
y: Math.min(box1.y, box2.y),
x2: Math.max(box1.x2, box2.x2),
y2: Math.max(box1.y2, box2.y2)
});
var rectToBox = ({ x, y, width, height }) => ({
x,
y,
x2: x + width,
y2: y + height
});
var boxToRect = ({ x, y, x2, y2 }) => ({
x,
y,
width: x2 - x,
height: y2 - y
});
var nodeToRect = (node, nodeOrigin = [0, 0]) => {
const { x, y } = isInternalNodeBase(node) ? node.internals.positionAbsolute : getNodePositionWithOrigin(node, nodeOrigin);
return {
x,
y,
width: node.measured?.width ?? node.width ?? node.initialWidth ?? 0,
height: node.measured?.height ?? node.height ?? node.initialHeight ?? 0
};
};
var nodeToBox = (node, nodeOrigin = [0, 0]) => {
const { x, y } = isInternalNodeBase(node) ? node.internals.positionAbsolute : getNodePositionWithOrigin(node, nodeOrigin);
return {
x,
y,
x2: x + (node.measured?.width ?? node.width ?? node.initialWidth ?? 0),
y2: y + (node.measured?.height ?? node.height ?? node.initialHeight ?? 0)
};
};
var getBoundsOfRects = (rect1, rect2) => boxToRect(getBoundsOfBoxes(rectToBox(rect1), rectToBox(rect2)));
var getOverlappingArea = (rectA, rectB) => {
const xOverlap = Math.max(0, Math.min(rectA.x + rectA.width, rectB.x + rectB.width) - Math.max(rectA.x, rectB.x));
const yOverlap = Math.max(0, Math.min(rectA.y + rectA.height, rectB.y + rectB.height) - Math.max(rectA.y, rectB.y));
return Math.ceil(xOverlap * yOverlap);
};
var isRectObject = (obj) => isNumeric(obj.width) && isNumeric(obj.height) && isNumeric(obj.x) && isNumeric(obj.y);
var isNumeric = (n) => !isNaN(n) && isFinite(n);
var createDevWarn = (lib, helpUrl) => (id, message) => {
console.warn(`[${lib}]: ${message} Help: ${helpUrl}error#${id}`);
};
var snapPosition = (position, snapGrid = [1, 1]) => {
return {
x: snapGrid[0] * Math.round(position.x / snapGrid[0]),
y: snapGrid[1] * Math.round(position.y / snapGrid[1])
};
};
var pointToRendererPoint = ({ x, y }, [tx, ty, tScale], snapToGrid = false, snapGrid = [1, 1]) => {
const position = {
x: (x - tx) / tScale,
y: (y - ty) / tScale
};
return snapToGrid ? snapPosition(position, snapGrid) : position;
};
var rendererPointToPoint = ({ x, y }, [tx, ty, tScale]) => {
return {
x: x * tScale + tx,
y: y * tScale + ty
};
};
/**
* Parses a single padding value to a number
* @internal
* @param padding - Padding to parse
* @param viewport - Width or height of the viewport
* @returns The padding in pixels
*/
function parsePadding(padding, viewport) {
if (typeof padding === "number") return Math.floor((viewport - viewport / (1 + padding)) * .5);
if (typeof padding === "string" && padding.endsWith("px")) {
const paddingValue = parseFloat(padding);
if (!Number.isNaN(paddingValue)) return Math.floor(paddingValue);
}
if (typeof padding === "string" && padding.endsWith("%")) {
const paddingValue = parseFloat(padding);
if (!Number.isNaN(paddingValue)) return Math.floor(viewport * paddingValue * .01);
}
console.error(`The padding value "${padding}" is invalid. Please provide a number or a string with a valid unit (px or %).`);
return 0;
}
/**
* Parses the paddings to an object with top, right, bottom, left, x and y paddings
* @internal
* @param padding - Padding to parse
* @param width - Width of the viewport
* @param height - Height of the viewport
* @returns An object with the paddings in pixels
*/
function parsePaddings(padding, width, height) {
if (typeof padding === "string" || typeof padding === "number") {
const paddingY = parsePadding(padding, height);
const paddingX = parsePadding(padding, width);
return {
top: paddingY,
right: paddingX,
bottom: paddingY,
left: paddingX,
x: paddingX * 2,
y: paddingY * 2
};
}
if (typeof padding === "object") {
const top = parsePadding(padding.top ?? padding.y ?? 0, height);
const bottom = parsePadding(padding.bottom ?? padding.y ?? 0, height);
const left = parsePadding(padding.left ?? padding.x ?? 0, width);
const right = parsePadding(padding.right ?? padding.x ?? 0, width);
return {
top,
right,
bottom,
left,
x: left + right,
y: top + bottom
};
}
return {
top: 0,
right: 0,
bottom: 0,
left: 0,
x: 0,
y: 0
};
}
/**
* Calculates the resulting paddings if the new viewport is applied
* @internal
* @param bounds - Bounds to fit inside viewport
* @param x - X position of the viewport
* @param y - Y position of the viewport
* @param zoom - Zoom level of the viewport
* @param width - Width of the viewport
* @param height - Height of the viewport
* @returns An object with the minimum padding required to fit the bounds inside the viewport
*/
function calculateAppliedPaddings(bounds, x, y, zoom, width, height) {
const { x: left, y: top } = rendererPointToPoint(bounds, [
x,
y,
zoom
]);
const { x: boundRight, y: boundBottom } = rendererPointToPoint({
x: bounds.x + bounds.width,
y: bounds.y + bounds.height
}, [
x,
y,
zoom
]);
const right = width - boundRight;
const bottom = height - boundBottom;
return {
left: Math.floor(left),
top: Math.floor(top),
right: Math.floor(right),
bottom: Math.floor(bottom)
};
}
/**
* Returns a viewport that encloses the given bounds with padding.
* @public
* @remarks You can determine bounds of nodes with {@link getNodesBounds} and {@link getBoundsOfRects}
* @param bounds - Bounds to fit inside viewport.
* @param width - Width of the viewport.
* @param height - Height of the viewport.
* @param minZoom - Minimum zoom level of the resulting viewport.
* @param maxZoom - Maximum zoom level of the resulting viewport.
* @param padding - Padding around the bounds.
* @returns A transformed {@link Viewport} that encloses the given bounds which you can pass to e.g. {@link setViewport}.
* @example
* const { x, y, zoom } = getViewportForBounds(
* { x: 0, y: 0, width: 100, height: 100},
* 1200, 800, 0.5, 2);
*/
var getViewportForBounds = (bounds, width, height, minZoom, maxZoom, padding) => {
const p = parsePaddings(padding, width, height);
const xZoom = (width - p.x) / bounds.width;
const yZoom = (height - p.y) / bounds.height;
const clampedZoom = clamp(Math.min(xZoom, yZoom), minZoom, maxZoom);
const boundsCenterX = bounds.x + bounds.width / 2;
const boundsCenterY = bounds.y + bounds.height / 2;
const x = width / 2 - boundsCenterX * clampedZoom;
const y = height / 2 - boundsCenterY * clampedZoom;
const newPadding = calculateAppliedPaddings(bounds, x, y, clampedZoom, width, height);
const offset = {
left: Math.min(newPadding.left - p.left, 0),
top: Math.min(newPadding.top - p.top, 0),
right: Math.min(newPadding.right - p.right, 0),
bottom: Math.min(newPadding.bottom - p.bottom, 0)
};
return {
x: x - offset.left + offset.right,
y: y - offset.top + offset.bottom,
zoom: clampedZoom
};
};
var isMacOs = () => typeof navigator !== "undefined" && navigator?.userAgent?.indexOf("Mac") >= 0;
function isCoordinateExtent(extent) {
return extent !== void 0 && extent !== null && extent !== "parent";
}
function getNodeDimensions(node) {
return {
width: node.measured?.width ?? node.width ?? node.initialWidth ?? 0,
height: node.measured?.height ?? node.height ?? node.initialHeight ?? 0
};
}
function nodeHasDimensions(node) {
return (node.measured?.width ?? node.width ?? node.initialWidth) !== void 0 && (node.measured?.height ?? node.height ?? node.initialHeight) !== void 0;
}
/**
* Convert child position to absolute position
*
* @internal
* @param position
* @param parentId
* @param nodeLookup
* @param nodeOrigin
* @returns an internal node with an absolute position
*/
function evaluateAbsolutePosition(position, dimensions = {
width: 0,
height: 0
}, parentId, nodeLookup, nodeOrigin) {
const positionAbsolute = { ...position };
const parent = nodeLookup.get(parentId);
if (parent) {
const origin = parent.origin || nodeOrigin;
positionAbsolute.x += parent.internals.positionAbsolute.x - (dimensions.width ?? 0) * origin[0];
positionAbsolute.y += parent.internals.positionAbsolute.y - (dimensions.height ?? 0) * origin[1];
}
return positionAbsolute;
}
function areSetsEqual(a, b) {
if (a.size !== b.size) return false;
for (const item of a) if (!b.has(item)) return false;
return true;
}
/**
* Polyfill for Promise.withResolvers until we can use it in all browsers
* @internal
*/
function withResolvers() {
let resolve;
let reject;
return {
promise: new Promise((res, rej) => {
resolve = res;
reject = rej;
}),
resolve,
reject
};
}
function mergeAriaLabelConfig(partial) {
return {
...defaultAriaLabelConfig,
...partial || {}
};
}
function getPointerPosition(event, { snapGrid = [0, 0], snapToGrid = false, transform, containerBounds }) {
const { x, y } = getEventPosition(event);
const pointerPos = pointToRendererPoint({
x: x - (containerBounds?.left ?? 0),
y: y - (containerBounds?.top ?? 0)
}, transform);
const { x: xSnapped, y: ySnapped } = snapToGrid ? snapPosition(pointerPos, snapGrid) : pointerPos;
return {
xSnapped,
ySnapped,
...pointerPos
};
}
var getDimensions = (node) => ({
width: node.offsetWidth,
height: node.offsetHeight
});
var getHostForElement = (element) => element?.getRootNode?.() || window?.document;
var inputTags = [
"INPUT",
"SELECT",
"TEXTAREA"
];
function isInputDOMNode(event) {
const target = event.composedPath?.()?.[0] || event.target;
if (target?.nodeType !== 1) return false;
return inputTags.includes(target.nodeName) || target.hasAttribute("contenteditable") || !!target.closest(".nokey");
}
var isMouseEvent = (event) => "clientX" in event;
var getEventPosition = (event, bounds) => {
const isMouse = isMouseEvent(event);
const evtX = isMouse ? event.clientX : event.touches?.[0].clientX;
const evtY = isMouse ? event.clientY : event.touches?.[0].clientY;
return {
x: evtX - (bounds?.left ?? 0),
y: evtY - (bounds?.top ?? 0)
};
};
var getHandleBounds = (type, nodeElement, nodeBounds, zoom, nodeId) => {
const handles = nodeElement.querySelectorAll(`.${type}`);
if (!handles || !handles.length) return null;
return Array.from(handles).map((handle) => {
const handleBounds = handle.getBoundingClientRect();
return {
id: handle.getAttribute("data-handleid"),
type,
nodeId,
position: handle.getAttribute("data-handlepos"),
x: (handleBounds.left - nodeBounds.left) / zoom,
y: (handleBounds.top - nodeBounds.top) / zoom,
...getDimensions(handle)
};
});
};
function getBezierEdgeCenter({ sourceX, sourceY, targetX, targetY, sourceControlX, sourceControlY, targetControlX, targetControlY }) {
const centerX = sourceX * .125 + sourceControlX * .375 + targetControlX * .375 + targetX * .125;
const centerY = sourceY * .125 + sourceControlY * .375 + targetControlY * .375 + targetY * .125;
return [
centerX,
centerY,
Math.abs(centerX - sourceX),
Math.abs(centerY - sourceY)
];
}
function calculateControlOffset(distance, curvature) {
if (distance >= 0) return .5 * distance;
return curvature * 25 * Math.sqrt(-distance);
}
function getControlWithCurvature({ pos, x1, y1, x2, y2, c }) {
switch (pos) {
case Position.Left: return [x1 - calculateControlOffset(x1 - x2, c), y1];
case Position.Right: return [x1 + calculateControlOffset(x2 - x1, c), y1];
case Position.Top: return [x1, y1 - calculateControlOffset(y1 - y2, c)];
case Position.Bottom: return [x1, y1 + calculateControlOffset(y2 - y1, c)];
}
}
/**
* The `getBezierPath` util returns everything you need to render a bezier edge
*between two nodes.
* @public
* @returns A path string you can use in an SVG, the `labelX` and `labelY` position (center of path)
* and `offsetX`, `offsetY` between source handle and label.
* - `path`: the path to use in an SVG `` element.
* - `labelX`: the `x` position you can use to render a label for this edge.
* - `labelY`: the `y` position you can use to render a label for this edge.
* - `offsetX`: the absolute difference between the source `x` position and the `x` position of the
* middle of this path.
* - `offsetY`: the absolute difference between the source `y` position and the `y` position of the
* middle of this path.
* @example
* ```js
* const source = { x: 0, y: 20 };
* const target = { x: 150, y: 100 };
*
* const [path, labelX, labelY, offsetX, offsetY] = getBezierPath({
* sourceX: source.x,
* sourceY: source.y,
* sourcePosition: Position.Right,
* targetX: target.x,
* targetY: target.y,
* targetPosition: Position.Left,
*});
*```
*
* @remarks This function returns a tuple (aka a fixed-size array) to make it easier to
*work with multiple edge paths at once.
*/
function getBezierPath({ sourceX, sourceY, sourcePosition = Position.Bottom, targetX, targetY, targetPosition = Position.Top, curvature = .25 }) {
const [sourceControlX, sourceControlY] = getControlWithCurvature({
pos: sourcePosition,
x1: sourceX,
y1: sourceY,
x2: targetX,
y2: targetY,
c: curvature
});
const [targetControlX, targetControlY] = getControlWithCurvature({
pos: targetPosition,
x1: targetX,
y1: targetY,
x2: sourceX,
y2: sourceY,
c: curvature
});
const [labelX, labelY, offsetX, offsetY] = getBezierEdgeCenter({
sourceX,
sourceY,
targetX,
targetY,
sourceControlX,
sourceControlY,
targetControlX,
targetControlY
});
return [
`M${sourceX},${sourceY} C${sourceControlX},${sourceControlY} ${targetControlX},${targetControlY} ${targetX},${targetY}`,
labelX,
labelY,
offsetX,
offsetY
];
}
function getEdgeCenter({ sourceX, sourceY, targetX, targetY }) {
const xOffset = Math.abs(targetX - sourceX) / 2;
const centerX = targetX < sourceX ? targetX + xOffset : targetX - xOffset;
const yOffset = Math.abs(targetY - sourceY) / 2;
return [
centerX,
targetY < sourceY ? targetY + yOffset : targetY - yOffset,
xOffset,
yOffset
];
}
/**
* Returns the z-index for an edge based on the node it connects and whether it is selected.
* By default, edges are rendered below nodes. This behaviour is different for edges that are
* connected to nodes with a parent, as they are rendered above the parent node.
*/
function getElevatedEdgeZIndex({ sourceNode, targetNode, selected = false, zIndex = 0, elevateOnSelect = false, zIndexMode = "basic" }) {
if (zIndexMode === "manual") return zIndex;
return (elevateOnSelect && selected ? zIndex + 1e3 : zIndex) + Math.max(sourceNode.parentId || elevateOnSelect && sourceNode.selected ? sourceNode.internals.z : 0, targetNode.parentId || elevateOnSelect && targetNode.selected ? targetNode.internals.z : 0);
}
function isEdgeVisible({ sourceNode, targetNode, width, height, transform }) {
const edgeBox = getBoundsOfBoxes(nodeToBox(sourceNode), nodeToBox(targetNode));
if (edgeBox.x === edgeBox.x2) edgeBox.x2 += 1;
if (edgeBox.y === edgeBox.y2) edgeBox.y2 += 1;
return getOverlappingArea({
x: -transform[0] / transform[2],
y: -transform[1] / transform[2],
width: width / transform[2],
height: height / transform[2]
}, boxToRect(edgeBox)) > 0;
}
/**
* The default edge ID generator function. Generates an ID based on the source, target, and handles.
* @public
* @param params - The connection or edge to generate an ID for.
* @returns The generated edge ID.
*/
var getEdgeId = ({ source, sourceHandle, target, targetHandle }) => `xy-edge__${source}${sourceHandle || ""}-${target}${targetHandle || ""}`;
var connectionExists = (edge, edges) => {
return edges.some((el) => el.source === edge.source && el.target === edge.target && (el.sourceHandle === edge.sourceHandle || !el.sourceHandle && !edge.sourceHandle) && (el.targetHandle === edge.targetHandle || !el.targetHandle && !edge.targetHandle));
};
/**
* This util is a convenience function to add a new Edge to an array of edges. It also performs some validation to make sure you don't add an invalid edge or duplicate an existing one.
* @public
* @param edgeParams - Either an `Edge` or a `Connection` you want to add.
* @param edges - The array of all current edges.
* @param options - Optional configuration object.
* @returns A new array of edges with the new edge added.
*
* @remarks If an edge with the same `target` and `source` already exists (and the same
*`targetHandle` and `sourceHandle` if those are set), then this util won't add
*a new edge even if the `id` property is different.
*
*/
var addEdge$1 = (edgeParams, edges, options = {}) => {
if (!edgeParams.source || !edgeParams.target) {
options.onError?.("006", errorMessages["error006"]());
return edges;
}
const edgeIdGenerator = options.getEdgeId || getEdgeId;
let edge;
if (isEdgeBase(edgeParams)) edge = { ...edgeParams };
else edge = {
...edgeParams,
id: edgeIdGenerator(edgeParams)
};
if (connectionExists(edge, edges)) return edges;
if (edge.sourceHandle === null) delete edge.sourceHandle;
if (edge.targetHandle === null) delete edge.targetHandle;
return edges.concat(edge);
};
/**
* A handy utility to update an existing [`Edge`](/api-reference/types/edge) with new properties.
*This searches your edge array for an edge with a matching `id` and updates its
*properties with the connection you provide.
* @public
* @param oldEdge - The edge you want to update.
* @param newConnection - The new connection you want to update the edge with.
* @param edges - The array of all current edges.
* @returns The updated edges array.
*
* @example
* ```js
*const onReconnect = useCallback(
* (oldEdge: Edge, newConnection: Connection) => setEdges((els) => reconnectEdge(oldEdge, newConnection, els)),[]);
*```
*/
var reconnectEdge$1 = (oldEdge, newConnection, edges, options = { shouldReplaceId: true }) => {
const { id: oldEdgeId, ...rest } = oldEdge;
if (!newConnection.source || !newConnection.target) {
options.onError?.("006", errorMessages["error006"]());
return edges;
}
if (!edges.find((e) => e.id === oldEdge.id)) {
options.onError?.("007", errorMessages["error007"](oldEdgeId));
return edges;
}
const edgeIdGenerator = options.getEdgeId || getEdgeId;
const edge = {
...rest,
id: options.shouldReplaceId ? edgeIdGenerator(newConnection) : oldEdgeId,
source: newConnection.source,
target: newConnection.target,
sourceHandle: newConnection.sourceHandle,
targetHandle: newConnection.targetHandle
};
return edges.filter((e) => e.id !== oldEdgeId).concat(edge);
};
/**
* Calculates the straight line path between two points.
* @public
* @returns A path string you can use in an SVG, the `labelX` and `labelY` position (center of path)
* and `offsetX`, `offsetY` between source handle and label.
*
* - `path`: the path to use in an SVG `` element.
* - `labelX`: the `x` position you can use to render a label for this edge.
* - `labelY`: the `y` position you can use to render a label for this edge.
* - `offsetX`: the absolute difference between the source `x` position and the `x` position of the
* middle of this path.
* - `offsetY`: the absolute difference between the source `y` position and the `y` position of the
* middle of this path.
* @example
* ```js
* const source = { x: 0, y: 20 };
* const target = { x: 150, y: 100 };
*
* const [path, labelX, labelY, offsetX, offsetY] = getStraightPath({
* sourceX: source.x,
* sourceY: source.y,
* sourcePosition: Position.Right,
* targetX: target.x,
* targetY: target.y,
* targetPosition: Position.Left,
* });
* ```
* @remarks This function returns a tuple (aka a fixed-size array) to make it easier to work with multiple edge paths at once.
*/
function getStraightPath({ sourceX, sourceY, targetX, targetY }) {
const [labelX, labelY, offsetX, offsetY] = getEdgeCenter({
sourceX,
sourceY,
targetX,
targetY
});
return [
`M ${sourceX},${sourceY}L ${targetX},${targetY}`,
labelX,
labelY,
offsetX,
offsetY
];
}
var handleDirections = {
[Position.Left]: {
x: -1,
y: 0
},
[Position.Right]: {
x: 1,
y: 0
},
[Position.Top]: {
x: 0,
y: -1
},
[Position.Bottom]: {
x: 0,
y: 1
}
};
var getDirection = ({ source, sourcePosition = Position.Bottom, target }) => {
if (sourcePosition === Position.Left || sourcePosition === Position.Right) return source.x < target.x ? {
x: 1,
y: 0
} : {
x: -1,
y: 0
};
return source.y < target.y ? {
x: 0,
y: 1
} : {
x: 0,
y: -1
};
};
var distance = (a, b) => Math.sqrt(Math.pow(b.x - a.x, 2) + Math.pow(b.y - a.y, 2));
function getPoints({ source, sourcePosition = Position.Bottom, target, targetPosition = Position.Top, center, offset, stepPosition }) {
const sourceDir = handleDirections[sourcePosition];
const targetDir = handleDirections[targetPosition];
const sourceGapped = {
x: source.x + sourceDir.x * offset,
y: source.y + sourceDir.y * offset
};
const targetGapped = {
x: target.x + targetDir.x * offset,
y: target.y + targetDir.y * offset
};
const dir = getDirection({
source: sourceGapped,
sourcePosition,
target: targetGapped
});
const dirAccessor = dir.x !== 0 ? "x" : "y";
const currDir = dir[dirAccessor];
let points = [];
let centerX, centerY;
const sourceGapOffset = {
x: 0,
y: 0
};
const targetGapOffset = {
x: 0,
y: 0
};
const [, , defaultOffsetX, defaultOffsetY] = getEdgeCenter({
sourceX: source.x,
sourceY: source.y,
targetX: target.x,
targetY: target.y
});
if (sourceDir[dirAccessor] * targetDir[dirAccessor] === -1) {
if (dirAccessor === "x") {
centerX = center.x ?? sourceGapped.x + (targetGapped.x - sourceGapped.x) * stepPosition;
centerY = center.y ?? (sourceGapped.y + targetGapped.y) / 2;
} else {
centerX = center.x ?? (sourceGapped.x + targetGapped.x) / 2;
centerY = center.y ?? sourceGapped.y + (targetGapped.y - sourceGapped.y) * stepPosition;
}
const verticalSplit = [{
x: centerX,
y: sourceGapped.y
}, {
x: centerX,
y: targetGapped.y
}];
const horizontalSplit = [{
x: sourceGapped.x,
y: centerY
}, {
x: targetGapped.x,
y: centerY
}];
if (sourceDir[dirAccessor] === currDir) points = dirAccessor === "x" ? verticalSplit : horizontalSplit;
else points = dirAccessor === "x" ? horizontalSplit : verticalSplit;
} else {
const sourceTarget = [{
x: sourceGapped.x,
y: targetGapped.y
}];
const targetSource = [{
x: targetGapped.x,
y: sourceGapped.y
}];
if (dirAccessor === "x") points = sourceDir.x === currDir ? targetSource : sourceTarget;
else points = sourceDir.y === currDir ? sourceTarget : targetSource;
if (sourcePosition === targetPosition) {
const diff = Math.abs(source[dirAccessor] - target[dirAccessor]);
if (diff <= offset) {
const gapOffset = Math.min(offset - 1, offset - diff);
if (sourceDir[dirAccessor] === currDir) sourceGapOffset[dirAccessor] = (sourceGapped[dirAccessor] > source[dirAccessor] ? -1 : 1) * gapOffset;
else targetGapOffset[dirAccessor] = (targetGapped[dirAccessor] > target[dirAccessor] ? -1 : 1) * gapOffset;
}
}
if (sourcePosition !== targetPosition) {
const dirAccessorOpposite = dirAccessor === "x" ? "y" : "x";
const isSameDir = sourceDir[dirAccessor] === targetDir[dirAccessorOpposite];
const sourceGtTargetOppo = sourceGapped[dirAccessorOpposite] > targetGapped[dirAccessorOpposite];
const sourceLtTargetOppo = sourceGapped[dirAccessorOpposite] < targetGapped[dirAccessorOpposite];
if (sourceDir[dirAccessor] === 1 && (!isSameDir && sourceGtTargetOppo || isSameDir && sourceLtTargetOppo) || sourceDir[dirAccessor] !== 1 && (!isSameDir && sourceLtTargetOppo || isSameDir && sourceGtTargetOppo)) points = dirAccessor === "x" ? sourceTarget : targetSource;
}
const sourceGapPoint = {
x: sourceGapped.x + sourceGapOffset.x,
y: sourceGapped.y + sourceGapOffset.y
};
const targetGapPoint = {
x: targetGapped.x + targetGapOffset.x,
y: targetGapped.y + targetGapOffset.y
};
if (Math.max(Math.abs(sourceGapPoint.x - points[0].x), Math.abs(targetGapPoint.x - points[0].x)) >= Math.max(Math.abs(sourceGapPoint.y - points[0].y), Math.abs(targetGapPoint.y - points[0].y))) {
centerX = (sourceGapPoint.x + targetGapPoint.x) / 2;
centerY = points[0].y;
} else {
centerX = points[0].x;
centerY = (sourceGapPoint.y + targetGapPoint.y) / 2;
}
}
const gappedSource = {
x: sourceGapped.x + sourceGapOffset.x,
y: sourceGapped.y + sourceGapOffset.y
};
const gappedTarget = {
x: targetGapped.x + targetGapOffset.x,
y: targetGapped.y + targetGapOffset.y
};
return [
[
source,
...gappedSource.x !== points[0].x || gappedSource.y !== points[0].y ? [gappedSource] : [],
...points,
...gappedTarget.x !== points[points.length - 1].x || gappedTarget.y !== points[points.length - 1].y ? [gappedTarget] : [],
target
],
centerX,
centerY,
defaultOffsetX,
defaultOffsetY
];
}
function getBend(a, b, c, size) {
const bendSize = Math.min(distance(a, b) / 2, distance(b, c) / 2, size);
const { x, y } = b;
if (a.x === x && x === c.x || a.y === y && y === c.y) return `L${x} ${y}`;
if (a.y === y) {
const xDir = a.x < c.x ? -1 : 1;
const yDir = a.y < c.y ? 1 : -1;
return `L ${x + bendSize * xDir},${y}Q ${x},${y} ${x},${y + bendSize * yDir}`;
}
const xDir = a.x < c.x ? 1 : -1;
return `L ${x},${y + bendSize * (a.y < c.y ? -1 : 1)}Q ${x},${y} ${x + bendSize * xDir},${y}`;
}
/**
* The `getSmoothStepPath` util returns everything you need to render a stepped path
* between two nodes. The `borderRadius` property can be used to choose how rounded
* the corners of those steps are.
* @public
* @returns A path string you can use in an SVG, the `labelX` and `labelY` position (center of path)
* and `offsetX`, `offsetY` between source handle and label.
*
* - `path`: the path to use in an SVG `` element.
* - `labelX`: the `x` position you can use to render a label for this edge.
* - `labelY`: the `y` position you can use to render a label for this edge.
* - `offsetX`: the absolute difference between the source `x` position and the `x` position of the
* middle of this path.
* - `offsetY`: the absolute difference between the source `y` position and the `y` position of the
* middle of this path.
* @example
* ```js
* const source = { x: 0, y: 20 };
* const target = { x: 150, y: 100 };
*
* const [path, labelX, labelY, offsetX, offsetY] = getSmoothStepPath({
* sourceX: source.x,
* sourceY: source.y,
* sourcePosition: Position.Right,
* targetX: target.x,
* targetY: target.y,
* targetPosition: Position.Left,
* });
* ```
* @remarks This function returns a tuple (aka a fixed-size array) to make it easier to work with multiple edge paths at once.
*/
function getSmoothStepPath({ sourceX, sourceY, sourcePosition = Position.Bottom, targetX, targetY, targetPosition = Position.Top, borderRadius = 5, centerX, centerY, offset = 20, stepPosition = .5 }) {
const [points, labelX, labelY, offsetX, offsetY] = getPoints({
source: {
x: sourceX,
y: sourceY
},
sourcePosition,
target: {
x: targetX,
y: targetY
},
targetPosition,
center: {
x: centerX,
y: centerY
},
offset,
stepPosition
});
let path = `M${points[0].x} ${points[0].y}`;
for (let i = 1; i < points.length - 1; i++) path += getBend(points[i - 1], points[i], points[i + 1], borderRadius);
path += `L${points[points.length - 1].x} ${points[points.length - 1].y}`;
return [
path,
labelX,
labelY,
offsetX,
offsetY
];
}
function isNodeInitialized(node) {
return node && !!(node.internals.handleBounds || node.handles?.length) && !!(node.measured.width || node.width || node.initialWidth);
}
function getEdgePosition(params) {
const { sourceNode, targetNode } = params;
if (!isNodeInitialized(sourceNode) || !isNodeInitialized(targetNode)) return null;
const sourceHandleBounds = sourceNode.internals.handleBounds || toHandleBounds(sourceNode.handles);
const targetHandleBounds = targetNode.internals.handleBounds || toHandleBounds(targetNode.handles);
const sourceHandle = getHandle$1(sourceHandleBounds?.source ?? [], params.sourceHandle);
const targetHandle = getHandle$1(params.connectionMode === ConnectionMode.Strict ? targetHandleBounds?.target ?? [] : (targetHandleBounds?.target ?? []).concat(targetHandleBounds?.source ?? []), params.targetHandle);
if (!sourceHandle || !targetHandle) {
params.onError?.("008", errorMessages["error008"](!sourceHandle ? "source" : "target", {
id: params.id,
sourceHandle: params.sourceHandle,
targetHandle: params.targetHandle
}));
return null;
}
const sourcePosition = sourceHandle?.position || Position.Bottom;
const targetPosition = targetHandle?.position || Position.Top;
const source = getHandlePosition(sourceNode, sourceHandle, sourcePosition);
const target = getHandlePosition(targetNode, targetHandle, targetPosition);
return {
sourceX: source.x,
sourceY: source.y,
targetX: target.x,
targetY: target.y,
sourcePosition,
targetPosition
};
}
function toHandleBounds(handles) {
if (!handles) return null;
const source = [];
const target = [];
for (const handle of handles) {
handle.width = handle.width ?? 1;
handle.height = handle.height ?? 1;
if (handle.type === "source") source.push(handle);
else if (handle.type === "target") target.push(handle);
}
return {
source,
target
};
}
function getHandlePosition(node, handle, fallbackPosition = Position.Left, center = false) {
const x = (handle?.x ?? 0) + node.internals.positionAbsolute.x;
const y = (handle?.y ?? 0) + node.internals.positionAbsolute.y;
const { width, height } = handle ?? getNodeDimensions(node);
if (center) return {
x: x + width / 2,
y: y + height / 2
};
switch (handle?.position ?? fallbackPosition) {
case Position.Top: return {
x: x + width / 2,
y
};
case Position.Right: return {
x: x + width,
y: y + height / 2
};
case Position.Bottom: return {
x: x + width / 2,
y: y + height
};
case Position.Left: return {
x,
y: y + height / 2
};
}
}
function getHandle$1(bounds, handleId) {
if (!bounds) return null;
return (!handleId ? bounds[0] : bounds.find((d) => d.id === handleId)) || null;
}
function getMarkerId(marker, id) {
if (!marker) return "";
if (typeof marker === "string") return marker;
return `${id ? `${id}__` : ""}${Object.keys(marker).sort().map((key) => `${key}=${marker[key]}`).join("&")}`;
}
function createMarkerIds(edges, { id, defaultColor, defaultMarkerStart, defaultMarkerEnd }) {
const ids = /* @__PURE__ */ new Set();
return edges.reduce((markers, edge) => {
[edge.markerStart || defaultMarkerStart, edge.markerEnd || defaultMarkerEnd].forEach((marker) => {
if (marker && typeof marker === "object") {
const markerId = getMarkerId(marker, id);
if (!ids.has(markerId)) {
markers.push({
id: markerId,
color: marker.color || defaultColor,
...marker
});
ids.add(markerId);
}
}
});
return markers;
}, []).sort((a, b) => a.id.localeCompare(b.id));
}
function getNodeToolbarTransform(nodeRect, viewport, position, offset, align) {
let alignmentOffset = .5;
if (align === "start") alignmentOffset = 0;
else if (align === "end") alignmentOffset = 1;
let pos = [(nodeRect.x + nodeRect.width * alignmentOffset) * viewport.zoom + viewport.x, nodeRect.y * viewport.zoom + viewport.y - offset];
let shift = [-100 * alignmentOffset, -100];
switch (position) {
case Position.Right:
pos = [(nodeRect.x + nodeRect.width) * viewport.zoom + viewport.x + offset, (nodeRect.y + nodeRect.height * alignmentOffset) * viewport.zoom + viewport.y];
shift = [0, -100 * alignmentOffset];
break;
case Position.Bottom:
pos[1] = (nodeRect.y + nodeRect.height) * viewport.zoom + viewport.y + offset;
shift[1] = 0;
break;
case Position.Left:
pos = [nodeRect.x * viewport.zoom + viewport.x - offset, (nodeRect.y + nodeRect.height * alignmentOffset) * viewport.zoom + viewport.y];
shift = [-100, -100 * alignmentOffset];
break;
}
return `translate(${pos[0]}px, ${pos[1]}px) translate(${shift[0]}%, ${shift[1]}%)`;
}
var alignXToPercent = {
left: 0,
center: 50,
right: 100
};
var alignYToPercent = {
top: 0,
center: 50,
bottom: 100
};
function getEdgeToolbarTransform(x, y, zoom, alignX = "center", alignY = "center") {
return `translate(${x}px, ${y}px) scale(${1 / zoom}) translate(${-(alignXToPercent[alignX] ?? 50)}%, ${-(alignYToPercent[alignY] ?? 50)}%)`;
}
var SELECTED_NODE_Z = 1e3;
var ROOT_PARENT_Z_INCREMENT = 10;
var defaultOptions = {
nodeOrigin: [0, 0],
nodeExtent: infiniteExtent,
elevateNodesOnSelect: true,
zIndexMode: "basic",
defaults: {}
};
var adoptUserNodesDefaultOptions = {
...defaultOptions,
checkEquality: true
};
function mergeObjects(base, incoming) {
const result = { ...base };
for (const key in incoming) if (incoming[key] !== void 0) result[key] = incoming[key];
return result;
}
function updateAbsolutePositions(nodeLookup, parentLookup, options) {
const _options = mergeObjects(defaultOptions, options);
for (const node of nodeLookup.values()) if (node.parentId) updateChildNode(node, nodeLookup, parentLookup, _options);
else {
const clampedPosition = clampPosition(getNodePositionWithOrigin(node, _options.nodeOrigin), isCoordinateExtent(node.extent) ? node.extent : _options.nodeExtent, getNodeDimensions(node));
node.internals.positionAbsolute = clampedPosition;
}
}
function parseHandles(userNode, internalNode) {
if (!userNode.handles) return !userNode.measured ? void 0 : internalNode?.internals.handleBounds;
const source = [];
const target = [];
for (const handle of userNode.handles) {
const handleBounds = {
id: handle.id,
width: handle.width ?? 1,
height: handle.height ?? 1,
nodeId: userNode.id,
x: handle.x,
y: handle.y,
position: handle.position,
type: handle.type
};
if (handle.type === "source") source.push(handleBounds);
else if (handle.type === "target") target.push(handleBounds);
}
return {
source,
target
};
}
function isManualZIndexMode(zIndexMode) {
return zIndexMode === "manual";
}
function adoptUserNodes(nodes, nodeLookup, parentLookup, options = {}) {
const _options = mergeObjects(adoptUserNodesDefaultOptions, options);
const rootParentIndex = { i: 0 };
const tmpLookup = new Map(nodeLookup);
const selectedNodeZ = _options?.elevateNodesOnSelect && !isManualZIndexMode(_options.zIndexMode) ? SELECTED_NODE_Z : 0;
let nodesInitialized = nodes.length > 0;
let hasSelectedNodes = false;
nodeLookup.clear();
parentLookup.clear();
for (const userNode of nodes) {
let internalNode = tmpLookup.get(userNode.id);
if (_options.checkEquality && userNode === internalNode?.internals.userNode) nodeLookup.set(userNode.id, internalNode);
else {
const clampedPosition = clampPosition(getNodePositionWithOrigin(userNode, _options.nodeOrigin), isCoordinateExtent(userNode.extent) ? userNode.extent : _options.nodeExtent, getNodeDimensions(userNode));
internalNode = {
..._options.defaults,
...userNode,
measured: {
width: userNode.measured?.width,
height: userNode.measured?.height
},
internals: {
positionAbsolute: clampedPosition,
handleBounds: parseHandles(userNode, internalNode),
z: calculateZ(userNode, selectedNodeZ, _options.zIndexMode),
userNode
}
};
nodeLookup.set(userNode.id, internalNode);
}
if ((internalNode.measured === void 0 || internalNode.measured.width === void 0 || internalNode.measured.height === void 0) && !internalNode.hidden) nodesInitialized = false;
if (userNode.parentId) updateChildNode(internalNode, nodeLookup, parentLookup, options, rootParentIndex);
hasSelectedNodes ||= userNode.selected ?? false;
}
return {
nodesInitialized,
hasSelectedNodes
};
}
function updateParentLookup(node, parentLookup) {
if (!node.parentId) return;
const childNodes = parentLookup.get(node.parentId);
if (childNodes) childNodes.set(node.id, node);
else parentLookup.set(node.parentId, new Map([[node.id, node]]));
}
/**
* Updates positionAbsolute and zIndex of a child node and the parentLookup.
*/
function updateChildNode(node, nodeLookup, parentLookup, options, rootParentIndex) {
const { elevateNodesOnSelect, nodeOrigin, nodeExtent, zIndexMode } = mergeObjects(defaultOptions, options);
const parentId = node.parentId;
const parentNode = nodeLookup.get(parentId);
if (!parentNode) {
console.warn(`Parent node ${parentId} not found. Please make sure that parent nodes are in front of their child nodes in the nodes array.`);
return;
}
updateParentLookup(node, parentLookup);
if (rootParentIndex && !parentNode.parentId && parentNode.internals.rootParentIndex === void 0 && zIndexMode === "auto") {
parentNode.internals.rootParentIndex = ++rootParentIndex.i;
parentNode.internals.z = parentNode.internals.z + rootParentIndex.i * ROOT_PARENT_Z_INCREMENT;
}
if (rootParentIndex && parentNode.internals.rootParentIndex !== void 0) rootParentIndex.i = parentNode.internals.rootParentIndex;
const { x, y, z } = calculateChildXYZ(node, parentNode, nodeOrigin, nodeExtent, elevateNodesOnSelect && !isManualZIndexMode(zIndexMode) ? SELECTED_NODE_Z : 0, zIndexMode);
const { positionAbsolute } = node.internals;
const positionChanged = x !== positionAbsolute.x || y !== positionAbsolute.y;
if (positionChanged || z !== node.internals.z) nodeLookup.set(node.id, {
...node,
internals: {
...node.internals,
positionAbsolute: positionChanged ? {
x,
y
} : positionAbsolute,
z
}
});
}
function calculateZ(node, selectedNodeZ, zIndexMode) {
const zIndex = isNumeric(node.zIndex) ? node.zIndex : 0;
if (isManualZIndexMode(zIndexMode)) return zIndex;
return zIndex + (node.selected ? selectedNodeZ : 0);
}
function calculateChildXYZ(childNode, parentNode, nodeOrigin, nodeExtent, selectedNodeZ, zIndexMode) {
const { x: parentX, y: parentY } = parentNode.internals.positionAbsolute;
const childDimensions = getNodeDimensions(childNode);
const positionWithOrigin = getNodePositionWithOrigin(childNode, nodeOrigin);
const clampedPosition = isCoordinateExtent(childNode.extent) ? clampPosition(positionWithOrigin, childNode.extent, childDimensions) : positionWithOrigin;
let absolutePosition = clampPosition({
x: parentX + clampedPosition.x,
y: parentY + clampedPosition.y
}, nodeExtent, childDimensions);
if (childNode.extent === "parent") absolutePosition = clampPositionToParent(absolutePosition, childDimensions, parentNode);
const childZ = calculateZ(childNode, selectedNodeZ, zIndexMode);
const parentZ = parentNode.internals.z ?? 0;
return {
x: absolutePosition.x,
y: absolutePosition.y,
z: parentZ >= childZ ? parentZ + 1 : childZ
};
}
function handleExpandParent(children, nodeLookup, parentLookup, nodeOrigin = [0, 0]) {
const changes = [];
const parentExpansions = /* @__PURE__ */ new Map();
for (const child of children) {
const parent = nodeLookup.get(child.parentId);
if (!parent) continue;
const expandedRect = getBoundsOfRects(parentExpansions.get(child.parentId)?.expandedRect ?? nodeToRect(parent), child.rect);
parentExpansions.set(child.parentId, {
expandedRect,
parent
});
}
if (parentExpansions.size > 0) parentExpansions.forEach(({ expandedRect, parent }, parentId) => {
const positionAbsolute = parent.internals.positionAbsolute;
const dimensions = getNodeDimensions(parent);
const origin = parent.origin ?? nodeOrigin;
const xChange = expandedRect.x < positionAbsolute.x ? Math.round(Math.abs(positionAbsolute.x - expandedRect.x)) : 0;
const yChange = expandedRect.y < positionAbsolute.y ? Math.round(Math.abs(positionAbsolute.y - expandedRect.y)) : 0;
const newWidth = Math.max(dimensions.width, Math.round(expandedRect.width));
const newHeight = Math.max(dimensions.height, Math.round(expandedRect.height));
const widthChange = (newWidth - dimensions.width) * origin[0];
const heightChange = (newHeight - dimensions.height) * origin[1];
if (xChange > 0 || yChange > 0 || widthChange || heightChange) {
changes.push({
id: parentId,
type: "position",
position: {
x: parent.position.x - xChange + widthChange,
y: parent.position.y - yChange + heightChange
}
});
parentLookup.get(parentId)?.forEach((childNode) => {
if (!children.some((child) => child.id === childNode.id)) changes.push({
id: childNode.id,
type: "position",
position: {
x: childNode.position.x + xChange,
y: childNode.position.y + yChange
}
});
});
}
if (dimensions.width < expandedRect.width || dimensions.height < expandedRect.height || xChange || yChange) changes.push({
id: parentId,
type: "dimensions",
setAttributes: true,
dimensions: {
width: newWidth + (xChange ? origin[0] * xChange - widthChange : 0),
height: newHeight + (yChange ? origin[1] * yChange - heightChange : 0)
}
});
});
return changes;
}
function updateNodeInternals(updates, nodeLookup, parentLookup, domNode, nodeOrigin, nodeExtent, zIndexMode) {
const viewportNode = domNode?.querySelector(".xyflow__viewport");
let updatedInternals = false;
if (!viewportNode) return {
changes: [],
updatedInternals
};
const changes = [];
const style = window.getComputedStyle(viewportNode);
const { m22: zoom } = new window.DOMMatrixReadOnly(style.transform);
const parentExpandChildren = [];
for (const update of updates.values()) {
const node = nodeLookup.get(update.id);
if (!node) continue;
if (node.hidden) {
nodeLookup.set(node.id, {
...node,
internals: {
...node.internals,
handleBounds: void 0
}
});
updatedInternals = true;
continue;
}
const dimensions = getDimensions(update.nodeElement);
const dimensionChanged = node.measured.width !== dimensions.width || node.measured.height !== dimensions.height;
if (!!(dimensions.width && dimensions.height && (dimensionChanged || !node.internals.handleBounds || update.force))) {
const nodeBounds = update.nodeElement.getBoundingClientRect();
const extent = isCoordinateExtent(node.extent) ? node.extent : nodeExtent;
let { positionAbsolute } = node.internals;
if (node.parentId && node.extent === "parent") positionAbsolute = clampPositionToParent(positionAbsolute, dimensions, nodeLookup.get(node.parentId));
else if (extent) positionAbsolute = clampPosition(positionAbsolute, extent, dimensions);
const newNode = {
...node,
measured: dimensions,
internals: {
...node.internals,
positionAbsolute,
handleBounds: {
source: getHandleBounds("source", update.nodeElement, nodeBounds, zoom, node.id),
target: getHandleBounds("target", update.nodeElement, nodeBounds, zoom, node.id)
}
}
};
nodeLookup.set(node.id, newNode);
if (node.parentId) updateChildNode(newNode, nodeLookup, parentLookup, {
nodeOrigin,
zIndexMode
});
updatedInternals = true;
if (dimensionChanged) {
changes.push({
id: node.id,
type: "dimensions",
dimensions
});
if (node.expandParent && node.parentId) parentExpandChildren.push({
id: node.id,
parentId: node.parentId,
rect: nodeToRect(newNode, nodeOrigin)
});
}
}
}
if (parentExpandChildren.length > 0) {
const parentExpandChanges = handleExpandParent(parentExpandChildren, nodeLookup, parentLookup, nodeOrigin);
changes.push(...parentExpandChanges);
}
return {
changes,
updatedInternals
};
}
async function panBy({ delta, panZoom, transform, translateExtent, width, height }) {
if (!panZoom || !delta.x && !delta.y) return false;
const nextViewport = await panZoom.setViewportConstrained({
x: transform[0] + delta.x,
y: transform[1] + delta.y,
zoom: transform[2]
}, [[0, 0], [width, height]], translateExtent);
return !!nextViewport && (nextViewport.x !== transform[0] || nextViewport.y !== transform[1] || nextViewport.k !== transform[2]);
}
/**
* this function adds the connection to the connectionLookup
* at the following keys: nodeId-type-handleId, nodeId-type and nodeId
* @param type type of the connection
* @param connection connection that should be added to the lookup
* @param connectionKey at which key the connection should be added
* @param connectionLookup reference to the connection lookup
* @param nodeId nodeId of the connection
* @param handleId handleId of the connection
*/
function addConnectionToLookup(type, connection, connectionKey, connectionLookup, nodeId, handleId) {
let key = nodeId;
const nodeMap = connectionLookup.get(key) || /* @__PURE__ */ new Map();
connectionLookup.set(key, nodeMap.set(connectionKey, connection));
key = `${nodeId}-${type}`;
const typeMap = connectionLookup.get(key) || /* @__PURE__ */ new Map();
connectionLookup.set(key, typeMap.set(connectionKey, connection));
if (handleId) {
key = `${nodeId}-${type}-${handleId}`;
const handleMap = connectionLookup.get(key) || /* @__PURE__ */ new Map();
connectionLookup.set(key, handleMap.set(connectionKey, connection));
}
}
function updateConnectionLookup(connectionLookup, edgeLookup, edges) {
connectionLookup.clear();
edgeLookup.clear();
for (const edge of edges) {
const { source: sourceNode, target: targetNode, sourceHandle = null, targetHandle = null } = edge;
const connection = {
edgeId: edge.id,
source: sourceNode,
target: targetNode,
sourceHandle,
targetHandle
};
const sourceKey = `${sourceNode}-${sourceHandle}--${targetNode}-${targetHandle}`;
addConnectionToLookup("source", connection, `${targetNode}-${targetHandle}--${sourceNode}-${sourceHandle}`, connectionLookup, sourceNode, sourceHandle);
addConnectionToLookup("target", connection, sourceKey, connectionLookup, targetNode, targetHandle);
edgeLookup.set(edge.id, edge);
}
}
function shallowNodeData(a, b) {
if (a === null || b === null) return false;
const _a = Array.isArray(a) ? a : [a];
const _b = Array.isArray(b) ? b : [b];
if (_a.length !== _b.length) return false;
for (let i = 0; i < _a.length; i++) if (_a[i].id !== _b[i].id || _a[i].type !== _b[i].type || !Object.is(_a[i].data, _b[i].data)) return false;
return true;
}
function isParentSelected(node, nodeLookup) {
if (!node.parentId) return false;
const parentNode = nodeLookup.get(node.parentId);
if (!parentNode) return false;
if (parentNode.selected) return true;
return isParentSelected(parentNode, nodeLookup);
}
function hasSelector(target, selector, domNode) {
let current = target;
do {
if (current?.matches?.(selector)) return true;
if (current === domNode) return false;
current = current?.parentElement;
} while (current);
return false;
}
function getDragItems(nodeLookup, nodesDraggable, mousePos, nodeId) {
const dragItems = /* @__PURE__ */ new Map();
for (const [id, node] of nodeLookup) if ((node.selected || node.id === nodeId) && (!node.parentId || !isParentSelected(node, nodeLookup)) && (node.draggable || nodesDraggable && typeof node.draggable === "undefined")) {
const internalNode = nodeLookup.get(id);
if (internalNode) dragItems.set(id, {
id,
position: internalNode.position || {
x: 0,
y: 0
},
distance: {
x: mousePos.x - internalNode.internals.positionAbsolute.x,
y: mousePos.y - internalNode.internals.positionAbsolute.y
},
extent: internalNode.extent,
parentId: internalNode.parentId,
origin: internalNode.origin,
expandParent: internalNode.expandParent,
internals: { positionAbsolute: internalNode.internals.positionAbsolute || {
x: 0,
y: 0
} },
measured: {
width: internalNode.measured.width ?? 0,
height: internalNode.measured.height ?? 0
}
});
}
return dragItems;
}
function getEventHandlerParams({ nodeId, dragItems, nodeLookup, dragging = true }) {
const nodesFromDragItems = [];
for (const [id, dragItem] of dragItems) {
const node = nodeLookup.get(id)?.internals.userNode;
if (node) nodesFromDragItems.push({
...node,
position: dragItem.position,
dragging
});
}
if (!nodeId) return [nodesFromDragItems[0], nodesFromDragItems];
const node = nodeLookup.get(nodeId)?.internals.userNode;
return [!node ? nodesFromDragItems[0] : {
...node,
position: dragItems.get(nodeId)?.position || node.position,
dragging
}, nodesFromDragItems];
}
/**
* If a selection is being dragged we want to apply the same snap offset to all nodes in the selection.
* This function calculates the snap offset based on the first node in the selection.
*/
function calculateSnapOffset({ dragItems, snapGrid, x, y }) {
const refDragItem = dragItems.values().next().value;
if (!refDragItem) return null;
const refPos = {
x: x - refDragItem.distance.x,
y: y - refDragItem.distance.y
};
const refPosSnapped = snapPosition(refPos, snapGrid);
return {
x: refPosSnapped.x - refPos.x,
y: refPosSnapped.y - refPos.y
};
}
function XYDrag({ onNodeMouseDown, getStoreItems, onDragStart, onDrag, onDragStop }) {
let lastPos = {
x: null,
y: null
};
let autoPanId = 0;
let dragItems = /* @__PURE__ */ new Map();
let autoPanStarted = false;
let mousePosition = {
x: 0,
y: 0
};
let containerBounds = null;
let dragStarted = false;
let d3Selection = null;
let abortDrag = false;
let nodePositionsChanged = false;
let dragEvent = null;
function update({ noDragClassName, handleSelector, domNode, isSelectable, nodeId, nodeClickDistance = 0 }) {
d3Selection = select_default$1(domNode);
function updateNodes({ x, y }) {
const { nodeLookup, nodeExtent, snapGrid, snapToGrid, nodeOrigin, onNodeDrag, onSelectionDrag, onError, updateNodePositions } = getStoreItems();
lastPos = {
x,
y
};
let hasChange = false;
const isMultiDrag = dragItems.size > 1;
const nodesBox = isMultiDrag && nodeExtent ? rectToBox(getInternalNodesBounds(dragItems)) : null;
const multiDragSnapOffset = isMultiDrag && snapToGrid ? calculateSnapOffset({
dragItems,
snapGrid,
x,
y
}) : null;
for (const [id, dragItem] of dragItems) {
if (!nodeLookup.has(id)) continue;
let nextPosition = {
x: x - dragItem.distance.x,
y: y - dragItem.distance.y
};
if (snapToGrid) nextPosition = multiDragSnapOffset ? {
x: Math.round(nextPosition.x + multiDragSnapOffset.x),
y: Math.round(nextPosition.y + multiDragSnapOffset.y)
} : snapPosition(nextPosition, snapGrid);
let adjustedNodeExtent = null;
if (isMultiDrag && nodeExtent && !dragItem.extent && nodesBox) {
const { positionAbsolute } = dragItem.internals;
const x1 = positionAbsolute.x - nodesBox.x + nodeExtent[0][0];
const x2 = positionAbsolute.x + dragItem.measured.width - nodesBox.x2 + nodeExtent[1][0];
const y1 = positionAbsolute.y - nodesBox.y + nodeExtent[0][1];
const y2 = positionAbsolute.y + dragItem.measured.height - nodesBox.y2 + nodeExtent[1][1];
adjustedNodeExtent = [[x1, y1], [x2, y2]];
}
const { position, positionAbsolute } = calculateNodePosition({
nodeId: id,
nextPosition,
nodeLookup,
nodeExtent: adjustedNodeExtent ? adjustedNodeExtent : nodeExtent,
nodeOrigin,
onError
});
hasChange = hasChange || dragItem.position.x !== position.x || dragItem.position.y !== position.y;
dragItem.position = position;
dragItem.internals.positionAbsolute = positionAbsolute;
}
nodePositionsChanged = nodePositionsChanged || hasChange;
if (!hasChange) return;
updateNodePositions(dragItems, true);
if (dragEvent && (onDrag || onNodeDrag || !nodeId && onSelectionDrag)) {
const [currentNode, currentNodes] = getEventHandlerParams({
nodeId,
dragItems,
nodeLookup
});
onDrag?.(dragEvent, dragItems, currentNode, currentNodes);
onNodeDrag?.(dragEvent, currentNode, currentNodes);
if (!nodeId) onSelectionDrag?.(dragEvent, currentNodes);
}
}
async function autoPan() {
if (!containerBounds) return;
const { transform, panBy, autoPanSpeed, autoPanOnNodeDrag } = getStoreItems();
if (!autoPanOnNodeDrag) {
autoPanStarted = false;
cancelAnimationFrame(autoPanId);
return;
}
const [xMovement, yMovement] = calcAutoPan(mousePosition, containerBounds, autoPanSpeed);
if (xMovement !== 0 || yMovement !== 0) {
lastPos.x = (lastPos.x ?? 0) - xMovement / transform[2];
lastPos.y = (lastPos.y ?? 0) - yMovement / transform[2];
if (await panBy({
x: xMovement,
y: yMovement
})) updateNodes(lastPos);
}
autoPanId = requestAnimationFrame(autoPan);
}
function startDrag(event) {
const { nodeLookup, multiSelectionActive, nodesDraggable, transform, snapGrid, snapToGrid, selectNodesOnDrag, onNodeDragStart, onSelectionDragStart, unselectNodesAndEdges } = getStoreItems();
dragStarted = true;
if ((!selectNodesOnDrag || !isSelectable) && !multiSelectionActive && nodeId) {
if (!nodeLookup.get(nodeId)?.selected) unselectNodesAndEdges();
}
if (isSelectable && selectNodesOnDrag && nodeId) onNodeMouseDown?.(nodeId);
const pointerPos = getPointerPosition(event.sourceEvent, {
transform,
snapGrid,
snapToGrid,
containerBounds
});
lastPos = pointerPos;
dragItems = getDragItems(nodeLookup, nodesDraggable, pointerPos, nodeId);
if (dragItems.size > 0 && (onDragStart || onNodeDragStart || !nodeId && onSelectionDragStart)) {
const [currentNode, currentNodes] = getEventHandlerParams({
nodeId,
dragItems,
nodeLookup
});
onDragStart?.(event.sourceEvent, dragItems, currentNode, currentNodes);
onNodeDragStart?.(event.sourceEvent, currentNode, currentNodes);
if (!nodeId) onSelectionDragStart?.(event.sourceEvent, currentNodes);
}
}
const d3DragInstance = drag_default().clickDistance(nodeClickDistance).on("start", (event) => {
const { domNode, nodeDragThreshold, transform, snapGrid, snapToGrid } = getStoreItems();
containerBounds = domNode?.getBoundingClientRect() || null;
abortDrag = false;
nodePositionsChanged = false;
dragEvent = event.sourceEvent;
if (nodeDragThreshold === 0) startDrag(event);
lastPos = getPointerPosition(event.sourceEvent, {
transform,
snapGrid,
snapToGrid,
containerBounds
});
mousePosition = getEventPosition(event.sourceEvent, containerBounds);
}).on("drag", (event) => {
const { autoPanOnNodeDrag, transform, snapGrid, snapToGrid, nodeDragThreshold, nodeLookup } = getStoreItems();
const pointerPos = getPointerPosition(event.sourceEvent, {
transform,
snapGrid,
snapToGrid,
containerBounds
});
dragEvent = event.sourceEvent;
if (event.sourceEvent.type === "touchmove" && event.sourceEvent.touches.length > 1 || nodeId && !nodeLookup.has(nodeId)) abortDrag = true;
if (abortDrag) return;
if (!autoPanStarted && autoPanOnNodeDrag && dragStarted) {
autoPanStarted = true;
autoPan();
}
if (!dragStarted) {
const currentMousePosition = getEventPosition(event.sourceEvent, containerBounds);
const x = currentMousePosition.x - mousePosition.x;
const y = currentMousePosition.y - mousePosition.y;
if (Math.sqrt(x * x + y * y) > nodeDragThreshold) startDrag(event);
}
if ((lastPos.x !== pointerPos.xSnapped || lastPos.y !== pointerPos.ySnapped) && dragItems && dragStarted) {
mousePosition = getEventPosition(event.sourceEvent, containerBounds);
updateNodes(pointerPos);
}
}).on("end", (event) => {
if (!dragStarted || abortDrag) {
if (abortDrag && dragItems.size > 0) getStoreItems().updateNodePositions(dragItems, false);
return;
}
autoPanStarted = false;
dragStarted = false;
cancelAnimationFrame(autoPanId);
if (dragItems.size > 0) {
const { nodeLookup, updateNodePositions, onNodeDragStop, onSelectionDragStop } = getStoreItems();
if (nodePositionsChanged) {
updateNodePositions(dragItems, false);
nodePositionsChanged = false;
}
if (onDragStop || onNodeDragStop || !nodeId && onSelectionDragStop) {
const [currentNode, currentNodes] = getEventHandlerParams({
nodeId,
dragItems,
nodeLookup,
dragging: false
});
onDragStop?.(event.sourceEvent, dragItems, currentNode, currentNodes);
onNodeDragStop?.(event.sourceEvent, currentNode, currentNodes);
if (!nodeId) onSelectionDragStop?.(event.sourceEvent, currentNodes);
}
}
}).filter((event) => {
const target = event.target;
return !event.button && (!noDragClassName || !hasSelector(target, `.${noDragClassName}`, domNode)) && (!handleSelector || hasSelector(target, handleSelector, domNode));
});
d3Selection.call(d3DragInstance);
}
function destroy() {
d3Selection?.on(".drag", null);
}
return {
update,
destroy
};
}
function getNodesWithinDistance(position, nodeLookup, distance) {
const nodes = [];
const rect = {
x: position.x - distance,
y: position.y - distance,
width: distance * 2,
height: distance * 2
};
for (const node of nodeLookup.values()) if (getOverlappingArea(rect, nodeToRect(node)) > 0) nodes.push(node);
return nodes;
}
var ADDITIONAL_DISTANCE = 250;
function getClosestHandle(position, connectionRadius, nodeLookup, fromHandle) {
let closestHandles = [];
let minDistance = Infinity;
const closeNodes = getNodesWithinDistance(position, nodeLookup, connectionRadius + ADDITIONAL_DISTANCE);
for (const node of closeNodes) {
const allHandles = [...node.internals.handleBounds?.source ?? [], ...node.internals.handleBounds?.target ?? []];
for (const handle of allHandles) {
if (fromHandle.nodeId === handle.nodeId && fromHandle.type === handle.type && fromHandle.id === handle.id) continue;
const { x, y } = getHandlePosition(node, handle, handle.position, true);
const distance = Math.sqrt(Math.pow(x - position.x, 2) + Math.pow(y - position.y, 2));
if (distance > connectionRadius) continue;
if (distance < minDistance) {
closestHandles = [{
...handle,
x,
y
}];
minDistance = distance;
} else if (distance === minDistance) closestHandles.push({
...handle,
x,
y
});
}
}
if (!closestHandles.length) return null;
if (closestHandles.length > 1) {
const oppositeHandleType = fromHandle.type === "source" ? "target" : "source";
return closestHandles.find((handle) => handle.type === oppositeHandleType) ?? closestHandles[0];
}
return closestHandles[0];
}
function getHandle(nodeId, handleType, handleId, nodeLookup, connectionMode, withAbsolutePosition = false) {
const node = nodeLookup.get(nodeId);
if (!node) return null;
const handles = connectionMode === "strict" ? node.internals.handleBounds?.[handleType] : [...node.internals.handleBounds?.source ?? [], ...node.internals.handleBounds?.target ?? []];
const handle = (handleId ? handles?.find((h) => h.id === handleId) : handles?.[0]) ?? null;
return handle && withAbsolutePosition ? {
...handle,
...getHandlePosition(node, handle, handle.position, true)
} : handle;
}
function getHandleType(edgeUpdaterType, handleDomNode) {
if (edgeUpdaterType) return edgeUpdaterType;
else if (handleDomNode?.classList.contains("target")) return "target";
else if (handleDomNode?.classList.contains("source")) return "source";
return null;
}
function isConnectionValid(isInsideConnectionRadius, isHandleValid) {
let isValid = null;
if (isHandleValid) isValid = true;
else if (isInsideConnectionRadius && !isHandleValid) isValid = false;
return isValid;
}
var alwaysValid = () => true;
function onPointerDown(event, { connectionMode, connectionRadius, handleId, nodeId, edgeUpdaterType, isTarget, domNode, nodeLookup, lib, autoPanOnConnect, flowId, panBy, cancelConnection, onConnectStart, onConnect, onConnectEnd, isValidConnection = alwaysValid, onReconnectEnd, updateConnection, getTransform, getFromHandle, autoPanSpeed, dragThreshold = 1, handleDomNode }) {
const doc = getHostForElement(event.target);
let autoPanId = 0;
let closestHandle;
const { x, y } = getEventPosition(event);
const handleType = getHandleType(edgeUpdaterType, handleDomNode);
const containerBounds = domNode?.getBoundingClientRect();
let connectionStarted = false;
if (!containerBounds || !handleType) return;
const fromHandleInternal = getHandle(nodeId, handleType, handleId, nodeLookup, connectionMode);
if (!fromHandleInternal) return;
let position = getEventPosition(event, containerBounds);
let autoPanStarted = false;
let connection = null;
let isValid = false;
let resultHandleDomNode = null;
function autoPan() {
if (!autoPanOnConnect || !containerBounds) return;
const [x, y] = calcAutoPan(position, containerBounds, autoPanSpeed);
panBy({
x,
y
});
autoPanId = requestAnimationFrame(autoPan);
}
const fromHandle = {
...fromHandleInternal,
nodeId,
type: handleType,
position: fromHandleInternal.position
};
const fromInternalNode = nodeLookup.get(nodeId);
let previousConnection = {
inProgress: true,
isValid: null,
from: getHandlePosition(fromInternalNode, fromHandle, Position.Left, true),
fromHandle,
fromPosition: fromHandle.position,
fromNode: fromInternalNode,
to: position,
toHandle: null,
toPosition: oppositePosition[fromHandle.position],
toNode: null,
pointer: position
};
function startConnection() {
connectionStarted = true;
updateConnection(previousConnection);
onConnectStart?.(event, {
nodeId,
handleId,
handleType
});
}
if (dragThreshold === 0) startConnection();
function onPointerMove(event) {
if (!connectionStarted) {
const { x: evtX, y: evtY } = getEventPosition(event);
const dx = evtX - x;
const dy = evtY - y;
if (!(dx * dx + dy * dy > dragThreshold * dragThreshold)) return;
startConnection();
}
if (!getFromHandle() || !fromHandle) {
onPointerUp(event);
return;
}
const transform = getTransform();
position = getEventPosition(event, containerBounds);
closestHandle = getClosestHandle(pointToRendererPoint(position, transform, false, [1, 1]), connectionRadius, nodeLookup, fromHandle);
if (!autoPanStarted) {
autoPan();
autoPanStarted = true;
}
const result = isValidHandle(event, {
handle: closestHandle,
connectionMode,
fromNodeId: nodeId,
fromHandleId: handleId,
fromType: isTarget ? "target" : "source",
isValidConnection,
doc,
lib,
flowId,
nodeLookup
});
resultHandleDomNode = result.handleDomNode;
connection = result.connection;
isValid = isConnectionValid(!!closestHandle, result.isValid);
const fromInternalNode = nodeLookup.get(nodeId);
const from = fromInternalNode ? getHandlePosition(fromInternalNode, fromHandle, Position.Left, true) : previousConnection.from;
const newConnection = {
...previousConnection,
from,
isValid,
to: result.toHandle && isValid ? rendererPointToPoint({
x: result.toHandle.x,
y: result.toHandle.y
}, transform) : position,
toHandle: result.toHandle,
toPosition: isValid && result.toHandle ? result.toHandle.position : oppositePosition[fromHandle.position],
toNode: result.toHandle ? nodeLookup.get(result.toHandle.nodeId) : null,
pointer: position
};
updateConnection(newConnection);
previousConnection = newConnection;
}
function onPointerUp(event) {
if ("touches" in event && event.touches.length > 0) return;
if (connectionStarted) {
if ((closestHandle || resultHandleDomNode) && connection && isValid) onConnect?.(connection);
const { inProgress, ...connectionState } = previousConnection;
const finalConnectionState = {
...connectionState,
toPosition: previousConnection.toHandle ? previousConnection.toPosition : null
};
onConnectEnd?.(event, finalConnectionState);
if (edgeUpdaterType) onReconnectEnd?.(event, finalConnectionState);
}
cancelConnection();
cancelAnimationFrame(autoPanId);
autoPanStarted = false;
isValid = false;
connection = null;
resultHandleDomNode = null;
doc.removeEventListener("mousemove", onPointerMove);
doc.removeEventListener("mouseup", onPointerUp);
doc.removeEventListener("touchmove", onPointerMove);
doc.removeEventListener("touchend", onPointerUp);
}
doc.addEventListener("mousemove", onPointerMove);
doc.addEventListener("mouseup", onPointerUp);
doc.addEventListener("touchmove", onPointerMove);
doc.addEventListener("touchend", onPointerUp);
}
function isValidHandle(event, { handle, connectionMode, fromNodeId, fromHandleId, fromType, doc, lib, flowId, isValidConnection = alwaysValid, nodeLookup }) {
const isTarget = fromType === "target";
const handleDomNode = handle ? doc.querySelector(`.${lib}-flow__handle[data-id="${flowId}-${handle?.nodeId}-${handle?.id}-${handle?.type}"]`) : null;
const { x, y } = getEventPosition(event);
const handleBelow = doc.elementFromPoint(x, y);
const handleToCheck = handleBelow?.classList.contains(`${lib}-flow__handle`) ? handleBelow : handleDomNode;
const result = {
handleDomNode: handleToCheck,
isValid: false,
connection: null,
toHandle: null
};
if (handleToCheck) {
const handleType = getHandleType(void 0, handleToCheck);
const handleNodeId = handleToCheck.getAttribute("data-nodeid");
const handleId = handleToCheck.getAttribute("data-handleid");
const connectable = handleToCheck.classList.contains("connectable");
const connectableEnd = handleToCheck.classList.contains("connectableend");
if (!handleNodeId || !handleType) return result;
const connection = {
source: isTarget ? handleNodeId : fromNodeId,
sourceHandle: isTarget ? handleId : fromHandleId,
target: isTarget ? fromNodeId : handleNodeId,
targetHandle: isTarget ? fromHandleId : handleId
};
result.connection = connection;
result.isValid = connectable && connectableEnd && (connectionMode === ConnectionMode.Strict ? isTarget && handleType === "source" || !isTarget && handleType === "target" : handleNodeId !== fromNodeId || handleId !== fromHandleId) && isValidConnection(connection);
result.toHandle = getHandle(handleNodeId, handleType, handleId, nodeLookup, connectionMode, true);
}
return result;
}
var XYHandle = {
onPointerDown,
isValid: isValidHandle
};
function XYMinimap({ domNode, panZoom, getTransform, getViewScale }) {
const selection = select_default$1(domNode);
function update({ translateExtent, width, height, zoomStep = 1, pannable = true, zoomable = true, inversePan = false }) {
const zoomHandler = (event) => {
if (event.sourceEvent.type !== "wheel" || !panZoom) return;
const transform = getTransform();
const factor = event.sourceEvent.ctrlKey && isMacOs() ? 10 : 1;
const pinchDelta = -event.sourceEvent.deltaY * (event.sourceEvent.deltaMode === 1 ? .05 : event.sourceEvent.deltaMode ? 1 : .002) * zoomStep;
const nextZoom = transform[2] * Math.pow(2, pinchDelta * factor);
panZoom.scaleTo(nextZoom);
};
let panStart = [0, 0];
const panStartHandler = (event) => {
if (event.sourceEvent.type === "mousedown" || event.sourceEvent.type === "touchstart") panStart = [event.sourceEvent.clientX ?? event.sourceEvent.touches[0].clientX, event.sourceEvent.clientY ?? event.sourceEvent.touches[0].clientY];
};
const panHandler = (event) => {
const transform = getTransform();
if (event.sourceEvent.type !== "mousemove" && event.sourceEvent.type !== "touchmove" || !panZoom) return;
const panCurrent = [event.sourceEvent.clientX ?? event.sourceEvent.touches[0].clientX, event.sourceEvent.clientY ?? event.sourceEvent.touches[0].clientY];
const panDelta = [panCurrent[0] - panStart[0], panCurrent[1] - panStart[1]];
panStart = panCurrent;
const moveScale = getViewScale() * Math.max(transform[2], Math.log(transform[2])) * (inversePan ? -1 : 1);
const position = {
x: transform[0] - panDelta[0] * moveScale,
y: transform[1] - panDelta[1] * moveScale
};
const extent = [[0, 0], [width, height]];
panZoom.setViewportConstrained({
x: position.x,
y: position.y,
zoom: transform[2]
}, extent, translateExtent);
};
const zoomAndPanHandler = zoom_default().on("start", panStartHandler).on("zoom", pannable ? panHandler : null).on("zoom.wheel", zoomable ? zoomHandler : null);
selection.call(zoomAndPanHandler, {});
}
function destroy() {
selection.on("zoom", null);
}
return {
update,
destroy,
pointer: pointer_default
};
}
var transformToViewport = (transform) => ({
x: transform.x,
y: transform.y,
zoom: transform.k
});
var viewportToTransform = ({ x, y, zoom }) => identity$1.translate(x, y).scale(zoom);
var isWrappedWithClass = (event, className) => event.target.closest(`.${className}`);
var isRightClickPan = (panOnDrag, usedButton) => usedButton === 2 && Array.isArray(panOnDrag) && panOnDrag.includes(2);
var defaultEase = (t) => ((t *= 2) <= 1 ? t * t * t : (t -= 2) * t * t + 2) / 2;
var getD3Transition = (selection, duration = 0, ease = defaultEase, onEnd = () => {}) => {
const hasDuration = typeof duration === "number" && duration > 0;
if (!hasDuration) onEnd();
return hasDuration ? selection.transition().duration(duration).ease(ease).on("end", onEnd) : selection;
};
var wheelDelta = (event) => {
const factor = event.ctrlKey && isMacOs() ? 10 : 1;
return -event.deltaY * (event.deltaMode === 1 ? .05 : event.deltaMode ? 1 : .002) * factor;
};
function createPanOnScrollHandler({ zoomPanValues, noWheelClassName, d3Selection, d3Zoom, panOnScrollMode, panOnScrollSpeed, zoomOnPinch, onPanZoomStart, onPanZoom, onPanZoomEnd }) {
return (event) => {
if (isWrappedWithClass(event, noWheelClassName)) {
if (event.ctrlKey) event.preventDefault();
return false;
}
event.preventDefault();
event.stopImmediatePropagation();
const currentZoom = d3Selection.property("__zoom").k || 1;
if (event.ctrlKey && zoomOnPinch) {
const point = pointer_default(event);
const pinchDelta = wheelDelta(event);
const zoom = currentZoom * Math.pow(2, pinchDelta);
d3Zoom.scaleTo(d3Selection, zoom, point, event);
return;
}
const deltaNormalize = event.deltaMode === 1 ? 20 : 1;
let deltaX = panOnScrollMode === PanOnScrollMode.Vertical ? 0 : event.deltaX * deltaNormalize;
let deltaY = panOnScrollMode === PanOnScrollMode.Horizontal ? 0 : event.deltaY * deltaNormalize;
if (!isMacOs() && event.shiftKey && panOnScrollMode !== PanOnScrollMode.Vertical) {
deltaX = event.deltaY * deltaNormalize;
deltaY = 0;
}
d3Zoom.translateBy(d3Selection, -(deltaX / currentZoom) * panOnScrollSpeed, -(deltaY / currentZoom) * panOnScrollSpeed, { internal: true });
const nextViewport = transformToViewport(d3Selection.property("__zoom"));
clearTimeout(zoomPanValues.panScrollTimeout);
if (!zoomPanValues.isPanScrolling) {
zoomPanValues.isPanScrolling = true;
onPanZoomStart?.(event, nextViewport);
} else {
onPanZoom?.(event, nextViewport);
zoomPanValues.panScrollTimeout = setTimeout(() => {
onPanZoomEnd?.(event, nextViewport);
zoomPanValues.isPanScrolling = false;
}, 150);
}
};
}
function createZoomOnScrollHandler({ noWheelClassName, preventScrolling, d3ZoomHandler }) {
return function(event, d) {
const isWheel = event.type === "wheel";
const preventZoom = !preventScrolling && isWheel && !event.ctrlKey;
const hasNoWheelClass = isWrappedWithClass(event, noWheelClassName);
if (event.ctrlKey && isWheel && hasNoWheelClass) event.preventDefault();
if (preventZoom || hasNoWheelClass) return null;
event.preventDefault();
d3ZoomHandler.call(this, event, d);
};
}
function createPanZoomStartHandler({ zoomPanValues, onDraggingChange, onPanZoomStart }) {
return (event) => {
if (event.sourceEvent?.internal) return;
const viewport = transformToViewport(event.transform);
zoomPanValues.mouseButton = event.sourceEvent?.button || 0;
zoomPanValues.isZoomingOrPanning = true;
zoomPanValues.prevViewport = viewport;
if (event.sourceEvent?.type === "mousedown") onDraggingChange(true);
if (onPanZoomStart) onPanZoomStart?.(event.sourceEvent, viewport);
};
}
function createPanZoomHandler({ zoomPanValues, panOnDrag, onPaneContextMenu, onTransformChange, onPanZoom }) {
return (event) => {
zoomPanValues.usedRightMouseButton = !!(onPaneContextMenu && isRightClickPan(panOnDrag, zoomPanValues.mouseButton ?? 0));
if (!event.sourceEvent?.sync) onTransformChange([
event.transform.x,
event.transform.y,
event.transform.k
]);
if (onPanZoom && !event.sourceEvent?.internal) onPanZoom?.(event.sourceEvent, transformToViewport(event.transform));
};
}
function createPanZoomEndHandler({ zoomPanValues, panOnDrag, panOnScroll, onDraggingChange, onPanZoomEnd, onPaneContextMenu }) {
return (event) => {
if (event.sourceEvent?.internal) return;
zoomPanValues.isZoomingOrPanning = false;
if (onPaneContextMenu && isRightClickPan(panOnDrag, zoomPanValues.mouseButton ?? 0) && !zoomPanValues.usedRightMouseButton && event.sourceEvent) onPaneContextMenu(event.sourceEvent);
zoomPanValues.usedRightMouseButton = false;
onDraggingChange(false);
if (onPanZoomEnd) {
const viewport = transformToViewport(event.transform);
zoomPanValues.prevViewport = viewport;
clearTimeout(zoomPanValues.timerId);
zoomPanValues.timerId = setTimeout(() => {
onPanZoomEnd?.(event.sourceEvent, viewport);
}, panOnScroll ? 150 : 0);
}
};
}
function createFilter({ zoomActivationKeyPressed, zoomOnScroll, zoomOnPinch, panOnDrag, panOnScroll, zoomOnDoubleClick, userSelectionActive, noWheelClassName, noPanClassName, lib, connectionInProgress }) {
return (event) => {
const zoomScroll = zoomActivationKeyPressed || zoomOnScroll;
const pinchZoom = zoomOnPinch && event.ctrlKey;
const isWheelEvent = event.type === "wheel";
if (event.button === 1 && event.type === "mousedown" && (isWrappedWithClass(event, `${lib}-flow__node`) || isWrappedWithClass(event, `${lib}-flow__edge`))) return true;
if (!panOnDrag && !zoomScroll && !panOnScroll && !zoomOnDoubleClick && !zoomOnPinch) return false;
if (userSelectionActive) return false;
if (connectionInProgress && !isWheelEvent) return false;
if (isWrappedWithClass(event, noWheelClassName) && isWheelEvent) return false;
if (isWrappedWithClass(event, noPanClassName) && (!isWheelEvent || panOnScroll && isWheelEvent && !zoomActivationKeyPressed)) return false;
if (!zoomOnPinch && event.ctrlKey && isWheelEvent) return false;
if (!zoomOnPinch && event.type === "touchstart" && event.touches?.length > 1) {
event.preventDefault();
return false;
}
if (!zoomScroll && !panOnScroll && !pinchZoom && isWheelEvent) return false;
if (!panOnDrag && (event.type === "mousedown" || event.type === "touchstart")) return false;
if (Array.isArray(panOnDrag) && !panOnDrag.includes(event.button) && event.type === "mousedown") return false;
const buttonAllowed = Array.isArray(panOnDrag) && panOnDrag.includes(event.button) || !event.button || event.button <= 1;
return (!event.ctrlKey || isWheelEvent) && buttonAllowed;
};
}
function XYPanZoom({ domNode, minZoom, maxZoom, translateExtent, viewport, onPanZoom, onPanZoomStart, onPanZoomEnd, onDraggingChange }) {
const zoomPanValues = {
isZoomingOrPanning: false,
usedRightMouseButton: false,
prevViewport: {},
mouseButton: 0,
timerId: void 0,
panScrollTimeout: void 0,
isPanScrolling: false
};
const bbox = domNode.getBoundingClientRect();
const d3ZoomInstance = zoom_default().scaleExtent([minZoom, maxZoom]).translateExtent(translateExtent);
const d3Selection = select_default$1(domNode).call(d3ZoomInstance);
setViewportConstrained({
x: viewport.x,
y: viewport.y,
zoom: clamp(viewport.zoom, minZoom, maxZoom)
}, [[0, 0], [bbox.width, bbox.height]], translateExtent);
const d3ZoomHandler = d3Selection.on("wheel.zoom");
const d3DblClickZoomHandler = d3Selection.on("dblclick.zoom");
d3ZoomInstance.wheelDelta(wheelDelta);
async function setTransform(transform, options) {
if (d3Selection) return new Promise((resolve) => {
d3ZoomInstance?.interpolate(options?.interpolate === "linear" ? value_default : zoom_default$1).transform(getD3Transition(d3Selection, options?.duration, options?.ease, () => resolve(true)), transform);
});
return false;
}
function update({ noWheelClassName, noPanClassName, onPaneContextMenu, userSelectionActive, panOnScroll, panOnDrag, panOnScrollMode, panOnScrollSpeed, preventScrolling, zoomOnPinch, zoomOnScroll, zoomOnDoubleClick, zoomActivationKeyPressed, lib, onTransformChange, connectionInProgress, paneClickDistance, selectionOnDrag }) {
if (userSelectionActive && !zoomPanValues.isZoomingOrPanning) destroy();
const isPanOnScroll = panOnScroll && !zoomActivationKeyPressed && !userSelectionActive;
d3ZoomInstance.clickDistance(selectionOnDrag ? Infinity : !isNumeric(paneClickDistance) || paneClickDistance < 0 ? 0 : paneClickDistance);
const wheelHandler = isPanOnScroll ? createPanOnScrollHandler({
zoomPanValues,
noWheelClassName,
d3Selection,
d3Zoom: d3ZoomInstance,
panOnScrollMode,
panOnScrollSpeed,
zoomOnPinch,
onPanZoomStart,
onPanZoom,
onPanZoomEnd
}) : createZoomOnScrollHandler({
noWheelClassName,
preventScrolling,
d3ZoomHandler
});
d3Selection.on("wheel.zoom", wheelHandler, { passive: false });
const startHandler = createPanZoomStartHandler({
zoomPanValues,
onDraggingChange,
onPanZoomStart
});
d3ZoomInstance.on("start", startHandler);
const panZoomHandler = createPanZoomHandler({
zoomPanValues,
panOnDrag,
onPaneContextMenu: !!onPaneContextMenu,
onPanZoom,
onTransformChange
});
d3ZoomInstance.on("zoom", panZoomHandler);
const panZoomEndHandler = createPanZoomEndHandler({
zoomPanValues,
panOnDrag,
panOnScroll,
onPaneContextMenu,
onPanZoomEnd,
onDraggingChange
});
d3ZoomInstance.on("end", panZoomEndHandler);
const filter = createFilter({
zoomActivationKeyPressed,
panOnDrag,
zoomOnScroll,
panOnScroll,
zoomOnDoubleClick,
zoomOnPinch,
userSelectionActive,
noPanClassName,
noWheelClassName,
lib,
connectionInProgress
});
d3ZoomInstance.filter(filter);
if (zoomOnDoubleClick) d3Selection.on("dblclick.zoom", d3DblClickZoomHandler);
else d3Selection.on("dblclick.zoom", null);
}
function destroy() {
d3ZoomInstance.on("zoom", null);
}
async function setViewportConstrained(viewport, extent, translateExtent) {
const nextTransform = viewportToTransform(viewport);
const contrainedTransform = d3ZoomInstance?.constrain()(nextTransform, extent, translateExtent);
if (contrainedTransform) await setTransform(contrainedTransform);
return contrainedTransform;
}
async function setViewport(viewport, options) {
const nextTransform = viewportToTransform(viewport);
await setTransform(nextTransform, options);
return nextTransform;
}
function syncViewport(viewport) {
if (d3Selection) {
const nextTransform = viewportToTransform(viewport);
const currentTransform = d3Selection.property("__zoom");
if (currentTransform.k !== viewport.zoom || currentTransform.x !== viewport.x || currentTransform.y !== viewport.y) d3ZoomInstance?.transform(d3Selection, nextTransform, null, { sync: true });
}
}
function getViewport() {
const transform$1 = d3Selection ? transform(d3Selection.node()) : {
x: 0,
y: 0,
k: 1
};
return {
x: transform$1.x,
y: transform$1.y,
zoom: transform$1.k
};
}
async function scaleTo(zoom, options) {
if (d3Selection) return new Promise((resolve) => {
d3ZoomInstance?.interpolate(options?.interpolate === "linear" ? value_default : zoom_default$1).scaleTo(getD3Transition(d3Selection, options?.duration, options?.ease, () => resolve(true)), zoom);
});
return false;
}
async function scaleBy(factor, options) {
if (d3Selection) return new Promise((resolve) => {
d3ZoomInstance?.interpolate(options?.interpolate === "linear" ? value_default : zoom_default$1).scaleBy(getD3Transition(d3Selection, options?.duration, options?.ease, () => resolve(true)), factor);
});
return false;
}
function setScaleExtent(scaleExtent) {
d3ZoomInstance?.scaleExtent(scaleExtent);
}
function setTranslateExtent(translateExtent) {
d3ZoomInstance?.translateExtent(translateExtent);
}
function setClickDistance(distance) {
const validDistance = !isNumeric(distance) || distance < 0 ? 0 : distance;
d3ZoomInstance?.clickDistance(validDistance);
}
return {
update,
destroy,
setViewport,
setViewportConstrained,
getViewport,
scaleTo,
scaleBy,
setScaleExtent,
setTranslateExtent,
syncViewport,
setClickDistance
};
}
/**
* Used to determine the variant of the resize control
*
* @public
*/
var ResizeControlVariant;
(function(ResizeControlVariant) {
ResizeControlVariant["Line"] = "line";
ResizeControlVariant["Handle"] = "handle";
})(ResizeControlVariant || (ResizeControlVariant = {}));
var XY_RESIZER_HANDLE_POSITIONS = [
"top-left",
"top-right",
"bottom-left",
"bottom-right"
];
var XY_RESIZER_LINE_POSITIONS = [
"top",
"right",
"bottom",
"left"
];
/**
* Get all connecting edges for a given set of nodes
* @param width - new width of the node
* @param prevWidth - previous width of the node
* @param height - new height of the node
* @param prevHeight - previous height of the node
* @param affectsX - whether to invert the resize direction for the x axis
* @param affectsY - whether to invert the resize direction for the y axis
* @returns array of two numbers representing the direction of the resize for each axis, 0 = no change, 1 = increase, -1 = decrease
*/
function getResizeDirection({ width, prevWidth, height, prevHeight, affectsX, affectsY }) {
const deltaWidth = width - prevWidth;
const deltaHeight = height - prevHeight;
const direction = [deltaWidth > 0 ? 1 : deltaWidth < 0 ? -1 : 0, deltaHeight > 0 ? 1 : deltaHeight < 0 ? -1 : 0];
if (deltaWidth && affectsX) direction[0] = direction[0] * -1;
if (deltaHeight && affectsY) direction[1] = direction[1] * -1;
return direction;
}
/**
* Parses the control position that is being dragged to dimensions that are being resized
* @param controlPosition - position of the control that is being dragged
* @returns isHorizontal, isVertical, affectsX, affectsY,
*/
function getControlDirection(controlPosition) {
return {
isHorizontal: controlPosition.includes("right") || controlPosition.includes("left"),
isVertical: controlPosition.includes("bottom") || controlPosition.includes("top"),
affectsX: controlPosition.includes("left"),
affectsY: controlPosition.includes("top")
};
}
function getLowerExtentClamp(lowerExtent, lowerBound) {
return Math.max(0, lowerBound - lowerExtent);
}
function getUpperExtentClamp(upperExtent, upperBound) {
return Math.max(0, upperExtent - upperBound);
}
function getSizeClamp(size, minSize, maxSize) {
return Math.max(0, minSize - size, size - maxSize);
}
function xor(a, b) {
return a ? !b : b;
}
/**
* Calculates new width & height and x & y of node after resize based on pointer position
* @description - Buckle up, this is a chunky one... If you want to determine the new dimensions of a node after a resize,
* you have to account for all possible restrictions: min/max width/height of the node, the maximum extent the node is allowed
* to move in (in this case: resize into) determined by the parent node, the minimal extent determined by child nodes
* with expandParent or extent: 'parent' set and oh yeah, these things also have to work with keepAspectRatio!
* The way this is done is by determining how much each of these restricting actually restricts the resize and then applying the
* strongest restriction. Because the resize affects x, y and width, height and width, height of a opposing side with keepAspectRatio,
* the resize amount is always kept in distX & distY amount (the distance in mouse movement)
* Instead of clamping each value, we first calculate the biggest 'clamp' (for the lack of a better name) and then apply it to all values.
* To complicate things nodeOrigin has to be taken into account as well. This is done by offsetting the nodes as if their origin is [0, 0],
* then calculating the restrictions as usual
* @param startValues - starting values of resize
* @param controlDirection - dimensions affected by the resize
* @param pointerPosition - the current pointer position corrected for snapping
* @param boundaries - minimum and maximum dimensions of the node
* @param keepAspectRatio - prevent changes of asprect ratio
* @returns x, y, width and height of the node after resize
*/
function getDimensionsAfterResize(startValues, controlDirection, pointerPosition, boundaries, keepAspectRatio, nodeOrigin, extent, childExtent) {
let { affectsX, affectsY } = controlDirection;
const { isHorizontal, isVertical } = controlDirection;
const isDiagonal = isHorizontal && isVertical;
const { xSnapped, ySnapped } = pointerPosition;
const { minWidth, maxWidth, minHeight, maxHeight } = boundaries;
const { x: startX, y: startY, width: startWidth, height: startHeight, aspectRatio } = startValues;
let distX = Math.floor(isHorizontal ? xSnapped - startValues.pointerX : 0);
let distY = Math.floor(isVertical ? ySnapped - startValues.pointerY : 0);
const newWidth = startWidth + (affectsX ? -distX : distX);
const newHeight = startHeight + (affectsY ? -distY : distY);
const originOffsetX = -nodeOrigin[0] * startWidth;
const originOffsetY = -nodeOrigin[1] * startHeight;
let clampX = getSizeClamp(newWidth, minWidth, maxWidth);
let clampY = getSizeClamp(newHeight, minHeight, maxHeight);
if (extent) {
let xExtentClamp = 0;
let yExtentClamp = 0;
if (affectsX && distX < 0) xExtentClamp = getLowerExtentClamp(startX + distX + originOffsetX, extent[0][0]);
else if (!affectsX && distX > 0) xExtentClamp = getUpperExtentClamp(startX + newWidth + originOffsetX, extent[1][0]);
if (affectsY && distY < 0) yExtentClamp = getLowerExtentClamp(startY + distY + originOffsetY, extent[0][1]);
else if (!affectsY && distY > 0) yExtentClamp = getUpperExtentClamp(startY + newHeight + originOffsetY, extent[1][1]);
clampX = Math.max(clampX, xExtentClamp);
clampY = Math.max(clampY, yExtentClamp);
}
if (childExtent) {
let xExtentClamp = 0;
let yExtentClamp = 0;
if (affectsX && distX > 0) xExtentClamp = getUpperExtentClamp(startX + distX, childExtent[0][0]);
else if (!affectsX && distX < 0) xExtentClamp = getLowerExtentClamp(startX + newWidth, childExtent[1][0]);
if (affectsY && distY > 0) yExtentClamp = getUpperExtentClamp(startY + distY, childExtent[0][1]);
else if (!affectsY && distY < 0) yExtentClamp = getLowerExtentClamp(startY + newHeight, childExtent[1][1]);
clampX = Math.max(clampX, xExtentClamp);
clampY = Math.max(clampY, yExtentClamp);
}
if (keepAspectRatio) {
if (isHorizontal) {
const aspectHeightClamp = getSizeClamp(newWidth / aspectRatio, minHeight, maxHeight) * aspectRatio;
clampX = Math.max(clampX, aspectHeightClamp);
if (extent) {
let aspectExtentClamp = 0;
if (!affectsX && !affectsY || affectsX && !affectsY && isDiagonal) aspectExtentClamp = getUpperExtentClamp(startY + originOffsetY + newWidth / aspectRatio, extent[1][1]) * aspectRatio;
else aspectExtentClamp = getLowerExtentClamp(startY + originOffsetY + (affectsX ? distX : -distX) / aspectRatio, extent[0][1]) * aspectRatio;
clampX = Math.max(clampX, aspectExtentClamp);
}
if (childExtent) {
let aspectExtentClamp = 0;
if (!affectsX && !affectsY || affectsX && !affectsY && isDiagonal) aspectExtentClamp = getLowerExtentClamp(startY + newWidth / aspectRatio, childExtent[1][1]) * aspectRatio;
else aspectExtentClamp = getUpperExtentClamp(startY + (affectsX ? distX : -distX) / aspectRatio, childExtent[0][1]) * aspectRatio;
clampX = Math.max(clampX, aspectExtentClamp);
}
}
if (isVertical) {
const aspectWidthClamp = getSizeClamp(newHeight * aspectRatio, minWidth, maxWidth) / aspectRatio;
clampY = Math.max(clampY, aspectWidthClamp);
if (extent) {
let aspectExtentClamp = 0;
if (!affectsX && !affectsY || affectsY && !affectsX && isDiagonal) aspectExtentClamp = getUpperExtentClamp(startX + newHeight * aspectRatio + originOffsetX, extent[1][0]) / aspectRatio;
else aspectExtentClamp = getLowerExtentClamp(startX + (affectsY ? distY : -distY) * aspectRatio + originOffsetX, extent[0][0]) / aspectRatio;
clampY = Math.max(clampY, aspectExtentClamp);
}
if (childExtent) {
let aspectExtentClamp = 0;
if (!affectsX && !affectsY || affectsY && !affectsX && isDiagonal) aspectExtentClamp = getLowerExtentClamp(startX + newHeight * aspectRatio, childExtent[1][0]) / aspectRatio;
else aspectExtentClamp = getUpperExtentClamp(startX + (affectsY ? distY : -distY) * aspectRatio, childExtent[0][0]) / aspectRatio;
clampY = Math.max(clampY, aspectExtentClamp);
}
}
}
distY = distY + (distY < 0 ? clampY : -clampY);
distX = distX + (distX < 0 ? clampX : -clampX);
if (keepAspectRatio) if (isDiagonal) if (newWidth > newHeight * aspectRatio) distY = (xor(affectsX, affectsY) ? -distX : distX) / aspectRatio;
else distX = (xor(affectsX, affectsY) ? -distY : distY) * aspectRatio;
else if (isHorizontal) {
distY = distX / aspectRatio;
affectsY = affectsX;
} else {
distX = distY * aspectRatio;
affectsX = affectsY;
}
const x = affectsX ? startX + distX : startX;
const y = affectsY ? startY + distY : startY;
return {
width: startWidth + (affectsX ? -distX : distX),
height: startHeight + (affectsY ? -distY : distY),
x: nodeOrigin[0] * distX * (!affectsX ? 1 : -1) + x,
y: nodeOrigin[1] * distY * (!affectsY ? 1 : -1) + y
};
}
var initPrevValues$1 = {
width: 0,
height: 0,
x: 0,
y: 0
};
var initStartValues = {
...initPrevValues$1,
pointerX: 0,
pointerY: 0,
aspectRatio: 1
};
function nodeToChildExtent(child, parent, nodeOrigin) {
const x = parent.position.x + child.position.x;
const y = parent.position.y + child.position.y;
const width = child.measured.width ?? 0;
const height = child.measured.height ?? 0;
const originOffsetX = nodeOrigin[0] * width;
const originOffsetY = nodeOrigin[1] * height;
return [[x - originOffsetX, y - originOffsetY], [x + width - originOffsetX, y + height - originOffsetY]];
}
function XYResizer({ domNode, nodeId, getStoreItems, onChange, onEnd }) {
const selection = select_default$1(domNode);
let params = {
controlDirection: getControlDirection("bottom-right"),
boundaries: {
minWidth: 0,
minHeight: 0,
maxWidth: Number.MAX_VALUE,
maxHeight: Number.MAX_VALUE
},
resizeDirection: void 0,
keepAspectRatio: false
};
function update({ controlPosition, boundaries, keepAspectRatio, resizeDirection, onResizeStart, onResize, onResizeEnd, shouldResize }) {
let prevValues = { ...initPrevValues$1 };
let startValues = { ...initStartValues };
params = {
boundaries,
resizeDirection,
keepAspectRatio,
controlDirection: getControlDirection(controlPosition)
};
let node = void 0;
let containerBounds = null;
let childNodes = [];
let parentNode = void 0;
let nodeExtent = void 0;
let childExtent = void 0;
let resizeDetected = false;
const dragHandler = drag_default().on("start", (event) => {
const { nodeLookup, transform, snapGrid, snapToGrid, nodeOrigin, paneDomNode } = getStoreItems();
node = nodeLookup.get(nodeId);
if (!node) return;
containerBounds = paneDomNode?.getBoundingClientRect() ?? null;
const { xSnapped, ySnapped } = getPointerPosition(event.sourceEvent, {
transform,
snapGrid,
snapToGrid,
containerBounds
});
prevValues = {
width: node.measured.width ?? 0,
height: node.measured.height ?? 0,
x: node.position.x ?? 0,
y: node.position.y ?? 0
};
startValues = {
...prevValues,
pointerX: xSnapped,
pointerY: ySnapped,
aspectRatio: prevValues.width / prevValues.height
};
parentNode = void 0;
nodeExtent = isCoordinateExtent(node.extent) ? node.extent : void 0;
if (node.parentId && (node.extent === "parent" || node.expandParent)) parentNode = nodeLookup.get(node.parentId);
if (parentNode && node.extent === "parent") nodeExtent = [[0, 0], [parentNode.measured.width, parentNode.measured.height]];
childNodes = [];
childExtent = void 0;
for (const [childId, child] of nodeLookup) if (child.parentId === nodeId) {
childNodes.push({
id: childId,
position: { ...child.position },
extent: child.extent
});
if (child.extent === "parent" || child.expandParent) {
const extent = nodeToChildExtent(child, node, child.origin ?? nodeOrigin);
if (childExtent) childExtent = [[Math.min(extent[0][0], childExtent[0][0]), Math.min(extent[0][1], childExtent[0][1])], [Math.max(extent[1][0], childExtent[1][0]), Math.max(extent[1][1], childExtent[1][1])]];
else childExtent = extent;
}
}
onResizeStart?.(event, { ...prevValues });
}).on("drag", (event) => {
const { transform, snapGrid, snapToGrid, nodeOrigin: storeNodeOrigin } = getStoreItems();
const pointerPosition = getPointerPosition(event.sourceEvent, {
transform,
snapGrid,
snapToGrid,
containerBounds
});
const childChanges = [];
if (!node) return;
const { x: prevX, y: prevY, width: prevWidth, height: prevHeight } = prevValues;
const change = {};
const nodeOrigin = node.origin ?? storeNodeOrigin;
const { width, height, x, y } = getDimensionsAfterResize(startValues, params.controlDirection, pointerPosition, params.boundaries, params.keepAspectRatio, nodeOrigin, nodeExtent, childExtent);
const isWidthChange = width !== prevWidth;
const isHeightChange = height !== prevHeight;
const isXPosChange = x !== prevX && isWidthChange;
const isYPosChange = y !== prevY && isHeightChange;
if (!isXPosChange && !isYPosChange && !isWidthChange && !isHeightChange) return;
if (isXPosChange || isYPosChange || nodeOrigin[0] === 1 || nodeOrigin[1] === 1) {
change.x = isXPosChange ? x : prevValues.x;
change.y = isYPosChange ? y : prevValues.y;
prevValues.x = change.x;
prevValues.y = change.y;
if (childNodes.length > 0) {
const xChange = x - prevX;
const yChange = y - prevY;
for (const childNode of childNodes) {
childNode.position = {
x: childNode.position.x - xChange + nodeOrigin[0] * (width - prevWidth),
y: childNode.position.y - yChange + nodeOrigin[1] * (height - prevHeight)
};
childChanges.push(childNode);
}
}
}
if (isWidthChange || isHeightChange) {
change.width = isWidthChange && (!params.resizeDirection || params.resizeDirection === "horizontal") ? width : prevValues.width;
change.height = isHeightChange && (!params.resizeDirection || params.resizeDirection === "vertical") ? height : prevValues.height;
prevValues.width = change.width;
prevValues.height = change.height;
}
if (parentNode && node.expandParent) {
const xLimit = nodeOrigin[0] * (change.width ?? 0);
if (change.x && change.x < xLimit) {
prevValues.x = xLimit;
startValues.x = startValues.x - (change.x - xLimit);
}
const yLimit = nodeOrigin[1] * (change.height ?? 0);
if (change.y && change.y < yLimit) {
prevValues.y = yLimit;
startValues.y = startValues.y - (change.y - yLimit);
}
}
const direction = getResizeDirection({
width: prevValues.width,
prevWidth,
height: prevValues.height,
prevHeight,
affectsX: params.controlDirection.affectsX,
affectsY: params.controlDirection.affectsY
});
const nextValues = {
...prevValues,
direction
};
if (shouldResize?.(event, nextValues) === false) return;
resizeDetected = true;
onResize?.(event, nextValues);
onChange(change, childChanges);
}).on("end", (event) => {
if (!resizeDetected) return;
onResizeEnd?.(event, { ...prevValues });
onEnd?.({ ...prevValues });
resizeDetected = false;
});
selection.call(dragHandler);
}
function destroy() {
selection.on(".drag", null);
}
return {
update,
destroy
};
}
//#endregion
//#region node_modules/use-sync-external-store/cjs/use-sync-external-store-shim.development.js
/**
* @license React
* use-sync-external-store-shim.development.js
*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
var require_use_sync_external_store_shim_development = /* @__PURE__ */ __commonJSMin(((exports) => {
(function() {
function is(x, y) {
return x === y && (0 !== x || 1 / x === 1 / y) || x !== x && y !== y;
}
function useSyncExternalStore$2(subscribe, getSnapshot) {
didWarnOld18Alpha || void 0 === React.startTransition || (didWarnOld18Alpha = !0, console.error("You are using an outdated, pre-release alpha of React 18 that does not support useSyncExternalStore. The use-sync-external-store shim will not work correctly. Upgrade to a newer pre-release."));
var value = getSnapshot();
if (!didWarnUncachedGetSnapshot) {
var cachedValue = getSnapshot();
objectIs(value, cachedValue) || (console.error("The result of getSnapshot should be cached to avoid an infinite loop"), didWarnUncachedGetSnapshot = !0);
}
cachedValue = useState({ inst: {
value,
getSnapshot
} });
var inst = cachedValue[0].inst, forceUpdate = cachedValue[1];
useLayoutEffect(function() {
inst.value = value;
inst.getSnapshot = getSnapshot;
checkIfSnapshotChanged(inst) && forceUpdate({ inst });
}, [
subscribe,
value,
getSnapshot
]);
useEffect(function() {
checkIfSnapshotChanged(inst) && forceUpdate({ inst });
return subscribe(function() {
checkIfSnapshotChanged(inst) && forceUpdate({ inst });
});
}, [subscribe]);
useDebugValue(value);
return value;
}
function checkIfSnapshotChanged(inst) {
var latestGetSnapshot = inst.getSnapshot;
inst = inst.value;
try {
var nextValue = latestGetSnapshot();
return !objectIs(inst, nextValue);
} catch (error) {
return !0;
}
}
function useSyncExternalStore$1(subscribe, getSnapshot) {
return getSnapshot();
}
"undefined" !== typeof __REACT_DEVTOOLS_GLOBAL_HOOK__ && "function" === typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStart && __REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStart(Error());
var React = require_react(), objectIs = "function" === typeof Object.is ? Object.is : is, useState = React.useState, useEffect = React.useEffect, useLayoutEffect = React.useLayoutEffect, useDebugValue = React.useDebugValue, didWarnOld18Alpha = !1, didWarnUncachedGetSnapshot = !1, shim = "undefined" === typeof window || "undefined" === typeof window.document || "undefined" === typeof window.document.createElement ? useSyncExternalStore$1 : useSyncExternalStore$2;
exports.useSyncExternalStore = void 0 !== React.useSyncExternalStore ? React.useSyncExternalStore : shim;
"undefined" !== typeof __REACT_DEVTOOLS_GLOBAL_HOOK__ && "function" === typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStop && __REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStop(Error());
})();
}));
//#endregion
//#region node_modules/use-sync-external-store/shim/index.js
var require_shim = /* @__PURE__ */ __commonJSMin(((exports, module) => {
module.exports = require_use_sync_external_store_shim_development();
}));
//#endregion
//#region node_modules/use-sync-external-store/cjs/use-sync-external-store-shim/with-selector.development.js
/**
* @license React
* use-sync-external-store-shim/with-selector.development.js
*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
var require_with_selector_development = /* @__PURE__ */ __commonJSMin(((exports) => {
(function() {
function is(x, y) {
return x === y && (0 !== x || 1 / x === 1 / y) || x !== x && y !== y;
}
"undefined" !== typeof __REACT_DEVTOOLS_GLOBAL_HOOK__ && "function" === typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStart && __REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStart(Error());
var React = require_react(), shim = require_shim(), objectIs = "function" === typeof Object.is ? Object.is : is, useSyncExternalStore = shim.useSyncExternalStore, useRef = React.useRef, useEffect = React.useEffect, useMemo = React.useMemo, useDebugValue = React.useDebugValue;
exports.useSyncExternalStoreWithSelector = function(subscribe, getSnapshot, getServerSnapshot, selector, isEqual) {
var instRef = useRef(null);
if (null === instRef.current) {
var inst = {
hasValue: !1,
value: null
};
instRef.current = inst;
} else inst = instRef.current;
instRef = useMemo(function() {
function memoizedSelector(nextSnapshot) {
if (!hasMemo) {
hasMemo = !0;
memoizedSnapshot = nextSnapshot;
nextSnapshot = selector(nextSnapshot);
if (void 0 !== isEqual && inst.hasValue) {
var currentSelection = inst.value;
if (isEqual(currentSelection, nextSnapshot)) return memoizedSelection = currentSelection;
}
return memoizedSelection = nextSnapshot;
}
currentSelection = memoizedSelection;
if (objectIs(memoizedSnapshot, nextSnapshot)) return currentSelection;
var nextSelection = selector(nextSnapshot);
if (void 0 !== isEqual && isEqual(currentSelection, nextSelection)) return memoizedSnapshot = nextSnapshot, currentSelection;
memoizedSnapshot = nextSnapshot;
return memoizedSelection = nextSelection;
}
var hasMemo = !1, memoizedSnapshot, memoizedSelection, maybeGetServerSnapshot = void 0 === getServerSnapshot ? null : getServerSnapshot;
return [function() {
return memoizedSelector(getSnapshot());
}, null === maybeGetServerSnapshot ? void 0 : function() {
return memoizedSelector(maybeGetServerSnapshot());
}];
}, [
getSnapshot,
getServerSnapshot,
selector,
isEqual
]);
var value = useSyncExternalStore(subscribe, instRef[0], instRef[1]);
useEffect(function() {
inst.hasValue = !0;
inst.value = value;
}, [value]);
useDebugValue(value);
return value;
};
"undefined" !== typeof __REACT_DEVTOOLS_GLOBAL_HOOK__ && "function" === typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStop && __REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStop(Error());
})();
}));
//#endregion
//#region node_modules/@xyflow/react/node_modules/zustand/esm/vanilla.mjs
var import_with_selector = /* @__PURE__ */ __toESM((/* @__PURE__ */ __commonJSMin(((exports, module) => {
module.exports = require_with_selector_development();
})))(), 1);
var createStoreImpl = (createState) => {
let state;
const listeners = /* @__PURE__ */ new Set();
const setState = (partial, replace) => {
const nextState = typeof partial === "function" ? partial(state) : partial;
if (!Object.is(nextState, state)) {
const previousState = state;
state = (replace != null ? replace : typeof nextState !== "object" || nextState === null) ? nextState : Object.assign({}, state, nextState);
listeners.forEach((listener) => listener(state, previousState));
}
};
const getState = () => state;
const getInitialState = () => initialState;
const subscribe = (listener) => {
listeners.add(listener);
return () => listeners.delete(listener);
};
const destroy = () => {
if ((import.meta.env ? import.meta.env.MODE : void 0) !== "production") console.warn("[DEPRECATED] The `destroy` method will be unsupported in a future version. Instead use unsubscribe function returned by subscribe. Everything will be garbage-collected if store is garbage-collected.");
listeners.clear();
};
const api = {
setState,
getState,
getInitialState,
subscribe,
destroy
};
const initialState = state = createState(setState, getState, api);
return api;
};
var createStore$1 = (createState) => createState ? createStoreImpl(createState) : createStoreImpl;
//#endregion
//#region node_modules/@xyflow/react/node_modules/zustand/esm/traditional.mjs
var { useDebugValue } = import_react.default;
var { useSyncExternalStoreWithSelector } = import_with_selector.default;
var identity = (arg) => arg;
function useStoreWithEqualityFn(api, selector = identity, equalityFn) {
const slice = useSyncExternalStoreWithSelector(api.subscribe, api.getState, api.getServerState || api.getInitialState, selector, equalityFn);
useDebugValue(slice);
return slice;
}
var createWithEqualityFnImpl = (createState, defaultEqualityFn) => {
const api = createStore$1(createState);
const useBoundStoreWithEqualityFn = (selector, equalityFn = defaultEqualityFn) => useStoreWithEqualityFn(api, selector, equalityFn);
Object.assign(useBoundStoreWithEqualityFn, api);
return useBoundStoreWithEqualityFn;
};
var createWithEqualityFn = (createState, defaultEqualityFn) => createState ? createWithEqualityFnImpl(createState, defaultEqualityFn) : createWithEqualityFnImpl;
//#endregion
//#region node_modules/@xyflow/react/node_modules/zustand/esm/shallow.mjs
function shallow$1(objA, objB) {
if (Object.is(objA, objB)) return true;
if (typeof objA !== "object" || objA === null || typeof objB !== "object" || objB === null) return false;
if (objA instanceof Map && objB instanceof Map) {
if (objA.size !== objB.size) return false;
for (const [key, value] of objA) if (!Object.is(value, objB.get(key))) return false;
return true;
}
if (objA instanceof Set && objB instanceof Set) {
if (objA.size !== objB.size) return false;
for (const value of objA) if (!objB.has(value)) return false;
return true;
}
const keysA = Object.keys(objA);
if (keysA.length !== Object.keys(objB).length) return false;
for (const keyA of keysA) if (!Object.prototype.hasOwnProperty.call(objB, keyA) || !Object.is(objA[keyA], objB[keyA])) return false;
return true;
}
//#endregion
//#region node_modules/@xyflow/react/dist/esm/index.js
var import_react_dom = /* @__PURE__ */ __toESM(require_react_dom());
var StoreContext = (0, import_react.createContext)(null);
var Provider$1 = StoreContext.Provider;
var zustandErrorMessage = errorMessages["error001"]("react");
/**
* This hook can be used to subscribe to internal state changes of the React Flow
* component. The `useStore` hook is re-exported from the [Zustand](https://github.com/pmndrs/zustand)
* state management library, so you should check out their docs for more details.
*
* @public
* @param selector - A selector function that returns a slice of the flow's internal state.
* Extracting or transforming just the state you need is a good practice to avoid unnecessary
* re-renders.
* @param equalityFn - A function to compare the previous and next value. This is incredibly useful
* for preventing unnecessary re-renders. Good sensible defaults are using `Object.is` or importing
* `zustand/shallow`, but you can be as granular as you like.
* @returns The selected state slice.
*
* @example
* ```ts
* const nodes = useStore((state) => state.nodes);
* ```
*
* @remarks This hook should only be used if there is no other way to access the internal
* state. For many of the common use cases, there are dedicated hooks available
* such as {@link useReactFlow}, {@link useViewport}, etc.
*/
function useStore(selector, equalityFn) {
const store = (0, import_react.useContext)(StoreContext);
if (store === null) throw new Error(zustandErrorMessage);
return useStoreWithEqualityFn(store, selector, equalityFn);
}
/**
* In some cases, you might need to access the store directly. This hook returns the store object which can be used on demand to access the state or dispatch actions.
*
* @returns The store object.
* @example
* ```ts
* const store = useStoreApi();
* ```
*
* @remarks This hook should only be used if there is no other way to access the internal
* state. For many of the common use cases, there are dedicated hooks available
* such as {@link useReactFlow}, {@link useViewport}, etc.
*/
function useStoreApi() {
const store = (0, import_react.useContext)(StoreContext);
if (store === null) throw new Error(zustandErrorMessage);
return (0, import_react.useMemo)(() => ({
getState: store.getState,
setState: store.setState,
subscribe: store.subscribe
}), [store]);
}
var style = { display: "none" };
var ariaLiveStyle = {
position: "absolute",
width: 1,
height: 1,
margin: -1,
border: 0,
padding: 0,
overflow: "hidden",
clip: "rect(0px, 0px, 0px, 0px)",
clipPath: "inset(100%)"
};
var ARIA_NODE_DESC_KEY = "react-flow__node-desc";
var ARIA_EDGE_DESC_KEY = "react-flow__edge-desc";
var ARIA_LIVE_MESSAGE = "react-flow__aria-live";
var ariaLiveSelector = (s) => s.ariaLiveMessage;
var ariaLabelConfigSelector = (s) => s.ariaLabelConfig;
function AriaLiveMessage({ rfId }) {
const ariaLiveMessage = useStore(ariaLiveSelector);
return (0, import_jsx_runtime.jsx)("div", {
id: `${ARIA_LIVE_MESSAGE}-${rfId}`,
"aria-live": "assertive",
"aria-atomic": "true",
style: ariaLiveStyle,
children: ariaLiveMessage
});
}
function A11yDescriptions({ rfId, disableKeyboardA11y }) {
const ariaLabelConfig = useStore(ariaLabelConfigSelector);
return (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
(0, import_jsx_runtime.jsx)("div", {
id: `${ARIA_NODE_DESC_KEY}-${rfId}`,
style,
children: disableKeyboardA11y ? ariaLabelConfig["node.a11yDescription.default"] : ariaLabelConfig["node.a11yDescription.keyboardDisabled"]
}),
(0, import_jsx_runtime.jsx)("div", {
id: `${ARIA_EDGE_DESC_KEY}-${rfId}`,
style,
children: ariaLabelConfig["edge.a11yDescription.default"]
}),
!disableKeyboardA11y && (0, import_jsx_runtime.jsx)(AriaLiveMessage, { rfId })
] });
}
/**
* The `` component helps you position content above the viewport.
* It is used internally by the [``](/api-reference/components/minimap)
* and [``](/api-reference/components/controls) components.
*
* @public
*
* @example
* ```jsx
*import { ReactFlow, Background, Panel } from '@xyflow/react';
*
*export default function Flow() {
* return (
*
* top-left
* top-center
* top-right
* bottom-left
* bottom-center
* bottom-right
*
* );
*}
*```
*/
var Panel = (0, import_react.forwardRef)(({ position = "top-left", children, className, style, ...rest }, ref) => {
return (0, import_jsx_runtime.jsx)("div", {
className: cc([
"react-flow__panel",
className,
...`${position}`.split("-")
]),
style,
ref,
...rest,
children
});
});
Panel.displayName = "Panel";
function Attribution({ proOptions, position = "bottom-right" }) {
if (proOptions?.hideAttribution) return null;
return (0, import_jsx_runtime.jsx)(Panel, {
position,
className: "react-flow__attribution",
"data-message": "Please only hide this attribution when you are subscribed to React Flow Pro: https://pro.reactflow.dev",
children: (0, import_jsx_runtime.jsx)("a", {
href: "https://reactflow.dev",
target: "_blank",
rel: "noopener noreferrer",
"aria-label": "React Flow attribution",
children: "React Flow"
})
});
}
var selector$m = (s) => {
const selectedNodes = [];
const selectedEdges = [];
for (const [, node] of s.nodeLookup) if (node.selected) selectedNodes.push(node.internals.userNode);
for (const [, edge] of s.edgeLookup) if (edge.selected) selectedEdges.push(edge);
return {
selectedNodes,
selectedEdges
};
};
var selectId = (obj) => obj.id;
function areEqual(a, b) {
return shallow$1(a.selectedNodes.map(selectId), b.selectedNodes.map(selectId)) && shallow$1(a.selectedEdges.map(selectId), b.selectedEdges.map(selectId));
}
function SelectionListenerInner({ onSelectionChange }) {
const store = useStoreApi();
const { selectedNodes, selectedEdges } = useStore(selector$m, areEqual);
(0, import_react.useEffect)(() => {
const params = {
nodes: selectedNodes,
edges: selectedEdges
};
onSelectionChange?.(params);
store.getState().onSelectionChangeHandlers.forEach((fn) => fn(params));
}, [
selectedNodes,
selectedEdges,
onSelectionChange
]);
return null;
}
var changeSelector = (s) => !!s.onSelectionChangeHandlers;
function SelectionListener({ onSelectionChange }) {
const storeHasSelectionChangeHandlers = useStore(changeSelector);
if (onSelectionChange || storeHasSelectionChangeHandlers) return (0, import_jsx_runtime.jsx)(SelectionListenerInner, { onSelectionChange });
return null;
}
var defaultNodeOrigin = [0, 0];
var defaultViewport = {
x: 0,
y: 0,
zoom: 1
};
var fieldsToTrack = [...[
"nodes",
"edges",
"defaultNodes",
"defaultEdges",
"onConnect",
"onConnectStart",
"onConnectEnd",
"onClickConnectStart",
"onClickConnectEnd",
"nodesDraggable",
"autoPanOnNodeFocus",
"nodesConnectable",
"nodesFocusable",
"edgesFocusable",
"edgesReconnectable",
"elevateNodesOnSelect",
"elevateEdgesOnSelect",
"minZoom",
"maxZoom",
"nodeExtent",
"onNodesChange",
"onEdgesChange",
"elementsSelectable",
"connectionMode",
"snapGrid",
"snapToGrid",
"translateExtent",
"connectOnClick",
"defaultEdgeOptions",
"fitView",
"fitViewOptions",
"onNodesDelete",
"onEdgesDelete",
"onDelete",
"onNodeDrag",
"onNodeDragStart",
"onNodeDragStop",
"onSelectionDrag",
"onSelectionDragStart",
"onSelectionDragStop",
"onMoveStart",
"onMove",
"onMoveEnd",
"noPanClassName",
"nodeOrigin",
"autoPanOnConnect",
"autoPanOnNodeDrag",
"onError",
"connectionRadius",
"isValidConnection",
"selectNodesOnDrag",
"nodeDragThreshold",
"connectionDragThreshold",
"onBeforeDelete",
"debug",
"autoPanSpeed",
"ariaLabelConfig",
"zIndexMode"
], "rfId"];
var selector$l = (s) => ({
setNodes: s.setNodes,
setEdges: s.setEdges,
setMinZoom: s.setMinZoom,
setMaxZoom: s.setMaxZoom,
setTranslateExtent: s.setTranslateExtent,
setNodeExtent: s.setNodeExtent,
reset: s.reset,
setDefaultNodesAndEdges: s.setDefaultNodesAndEdges
});
var initPrevValues = {
translateExtent: infiniteExtent,
nodeOrigin: defaultNodeOrigin,
minZoom: .5,
maxZoom: 2,
elementsSelectable: true,
noPanClassName: "nopan",
rfId: "1"
};
function StoreUpdater(props) {
const { setNodes, setEdges, setMinZoom, setMaxZoom, setTranslateExtent, setNodeExtent, reset, setDefaultNodesAndEdges } = useStore(selector$l, shallow$1);
const store = useStoreApi();
(0, import_react.useEffect)(() => {
setDefaultNodesAndEdges(props.defaultNodes, props.defaultEdges);
return () => {
previousFields.current = initPrevValues;
reset();
};
}, []);
const previousFields = (0, import_react.useRef)(initPrevValues);
(0, import_react.useEffect)(() => {
for (const fieldName of fieldsToTrack) {
const fieldValue = props[fieldName];
if (fieldValue === previousFields.current[fieldName]) continue;
if (typeof props[fieldName] === "undefined") continue;
if (fieldName === "nodes") setNodes(fieldValue);
else if (fieldName === "edges") setEdges(fieldValue);
else if (fieldName === "minZoom") setMinZoom(fieldValue);
else if (fieldName === "maxZoom") setMaxZoom(fieldValue);
else if (fieldName === "translateExtent") setTranslateExtent(fieldValue);
else if (fieldName === "nodeExtent") setNodeExtent(fieldValue);
else if (fieldName === "ariaLabelConfig") store.setState({ ariaLabelConfig: mergeAriaLabelConfig(fieldValue) });
else if (fieldName === "fitView") store.setState({ fitViewQueued: fieldValue });
else if (fieldName === "fitViewOptions") store.setState({ fitViewOptions: fieldValue });
else store.setState({ [fieldName]: fieldValue });
}
previousFields.current = props;
}, fieldsToTrack.map((fieldName) => props[fieldName]));
return null;
}
function getMediaQuery() {
if (typeof window === "undefined" || !window.matchMedia) return null;
return window.matchMedia("(prefers-color-scheme: dark)");
}
/**
* Hook for receiving the current color mode class 'dark' or 'light'.
*
* @internal
* @param colorMode - The color mode to use ('dark', 'light' or 'system')
*/
function useColorModeClass(colorMode) {
const [colorModeClass, setColorModeClass] = (0, import_react.useState)(colorMode === "system" ? null : colorMode);
(0, import_react.useEffect)(() => {
if (colorMode !== "system") {
setColorModeClass(colorMode);
return;
}
const mediaQuery = getMediaQuery();
const updateColorModeClass = () => setColorModeClass(mediaQuery?.matches ? "dark" : "light");
updateColorModeClass();
mediaQuery?.addEventListener("change", updateColorModeClass);
return () => {
mediaQuery?.removeEventListener("change", updateColorModeClass);
};
}, [colorMode]);
return colorModeClass !== null ? colorModeClass : getMediaQuery()?.matches ? "dark" : "light";
}
var defaultDoc = typeof document !== "undefined" ? document : null;
/**
* This hook lets you listen for specific key codes and tells you whether they are
* currently pressed or not.
*
* @public
* @param options - Options
*
* @example
* ```tsx
*import { useKeyPress } from '@xyflow/react';
*
*export default function () {
* const spacePressed = useKeyPress('Space');
* const cmdAndSPressed = useKeyPress(['Meta+s', 'Strg+s']);
*
* return (
*
* {spacePressed &&
Space pressed!
}
* {cmdAndSPressed &&
Cmd + S pressed!
}
*
* );
*}
*```
*/
function useKeyPress(keyCode = null, options = {
target: defaultDoc,
actInsideInputWithModifier: true
}) {
const [keyPressed, setKeyPressed] = (0, import_react.useState)(false);
const modifierPressed = (0, import_react.useRef)(false);
const pressedKeys = (0, import_react.useRef)(/* @__PURE__ */ new Set([]));
const [keyCodes, keysToWatch] = (0, import_react.useMemo)(() => {
if (keyCode !== null) {
const keys = (Array.isArray(keyCode) ? keyCode : [keyCode]).filter((kc) => typeof kc === "string").map((kc) => kc.replace("+", "\n").replace("\n\n", "\n+").split("\n"));
return [keys, keys.reduce((res, item) => res.concat(...item), [])];
}
return [[], []];
}, [keyCode]);
(0, import_react.useEffect)(() => {
const target = options?.target ?? defaultDoc;
const actInsideInputWithModifier = options?.actInsideInputWithModifier ?? true;
if (keyCode !== null) {
const downHandler = (event) => {
modifierPressed.current = event.ctrlKey || event.metaKey || event.shiftKey || event.altKey;
if ((!modifierPressed.current || modifierPressed.current && !actInsideInputWithModifier) && isInputDOMNode(event)) return false;
const keyOrCode = useKeyOrCode(event.code, keysToWatch);
pressedKeys.current.add(event[keyOrCode]);
if (isMatchingKey(keyCodes, pressedKeys.current, false)) {
const target = event.composedPath?.()?.[0] || event.target;
const isInteractiveElement = target?.nodeName === "BUTTON" || target?.nodeName === "A";
if (options.preventDefault !== false && (modifierPressed.current || !isInteractiveElement)) event.preventDefault();
setKeyPressed(true);
}
};
const upHandler = (event) => {
const keyOrCode = useKeyOrCode(event.code, keysToWatch);
if (isMatchingKey(keyCodes, pressedKeys.current, true)) {
setKeyPressed(false);
pressedKeys.current.clear();
} else pressedKeys.current.delete(event[keyOrCode]);
if (event.key === "Meta") pressedKeys.current.clear();
modifierPressed.current = false;
};
const resetHandler = () => {
pressedKeys.current.clear();
setKeyPressed(false);
};
target?.addEventListener("keydown", downHandler);
target?.addEventListener("keyup", upHandler);
window.addEventListener("blur", resetHandler);
window.addEventListener("contextmenu", resetHandler);
return () => {
target?.removeEventListener("keydown", downHandler);
target?.removeEventListener("keyup", upHandler);
window.removeEventListener("blur", resetHandler);
window.removeEventListener("contextmenu", resetHandler);
};
}
}, [keyCode, setKeyPressed]);
return keyPressed;
}
function isMatchingKey(keyCodes, pressedKeys, isUp) {
return keyCodes.filter((keys) => isUp || keys.length === pressedKeys.size).some((keys) => keys.every((k) => pressedKeys.has(k)));
}
function useKeyOrCode(eventCode, keysToWatch) {
return keysToWatch.includes(eventCode) ? "code" : "key";
}
/**
* Hook for getting viewport helper functions.
*
* @internal
* @returns viewport helper functions
*/
var useViewportHelper = () => {
const store = useStoreApi();
return (0, import_react.useMemo)(() => {
return {
zoomIn: async (options) => {
const { panZoom } = store.getState();
return panZoom ? panZoom.scaleBy(1.2, options) : false;
},
zoomOut: async (options) => {
const { panZoom } = store.getState();
return panZoom ? panZoom.scaleBy(1 / 1.2, options) : false;
},
zoomTo: async (zoomLevel, options) => {
const { panZoom } = store.getState();
return panZoom ? panZoom.scaleTo(zoomLevel, options) : false;
},
getZoom: () => store.getState().transform[2],
setViewport: async (viewport, options) => {
const { transform: [tX, tY, tZoom], panZoom } = store.getState();
if (!panZoom) return false;
await panZoom.setViewport({
x: viewport.x ?? tX,
y: viewport.y ?? tY,
zoom: viewport.zoom ?? tZoom
}, options);
return true;
},
getViewport: () => {
const [x, y, zoom] = store.getState().transform;
return {
x,
y,
zoom
};
},
setCenter: async (x, y, options) => {
return store.getState().setCenter(x, y, options);
},
fitBounds: async (bounds, options) => {
const { width, height, minZoom, maxZoom, panZoom } = store.getState();
const viewport = getViewportForBounds(bounds, width, height, minZoom, maxZoom, options?.padding ?? .1);
if (!panZoom) return false;
await panZoom.setViewport(viewport, {
duration: options?.duration,
ease: options?.ease,
interpolate: options?.interpolate
});
return true;
},
screenToFlowPosition: (clientPosition, options = {}) => {
const { transform, snapGrid, snapToGrid, domNode } = store.getState();
if (!domNode) return clientPosition;
const { x: domX, y: domY } = domNode.getBoundingClientRect();
const correctedPosition = {
x: clientPosition.x - domX,
y: clientPosition.y - domY
};
const _snapGrid = options.snapGrid ?? snapGrid;
return pointToRendererPoint(correctedPosition, transform, options.snapToGrid ?? snapToGrid, _snapGrid);
},
flowToScreenPosition: (flowPosition) => {
const { transform, domNode } = store.getState();
if (!domNode) return flowPosition;
const { x: domX, y: domY } = domNode.getBoundingClientRect();
const rendererPosition = rendererPointToPoint(flowPosition, transform);
return {
x: rendererPosition.x + domX,
y: rendererPosition.y + domY
};
}
};
}, []);
};
function applyChanges(changes, elements) {
const updatedElements = [];
const changesMap = /* @__PURE__ */ new Map();
const addItemChanges = [];
for (const change of changes) if (change.type === "add") {
addItemChanges.push(change);
continue;
} else if (change.type === "remove" || change.type === "replace") changesMap.set(change.id, [change]);
else {
const elementChanges = changesMap.get(change.id);
if (elementChanges) elementChanges.push(change);
else changesMap.set(change.id, [change]);
}
for (const element of elements) {
const changes = changesMap.get(element.id);
if (!changes) {
updatedElements.push(element);
continue;
}
if (changes[0].type === "remove") continue;
if (changes[0].type === "replace") {
updatedElements.push({ ...changes[0].item });
continue;
}
/**
* For other types of changes, we want to start with a shallow copy of the
* object so React knows this element has changed. Sequential changes will
* each _mutate_ this object, so there's only ever one copy.
*/
const updatedElement = { ...element };
for (const change of changes) applyChange(change, updatedElement);
updatedElements.push(updatedElement);
}
if (addItemChanges.length) addItemChanges.forEach((change) => {
if (change.index !== void 0) updatedElements.splice(change.index, 0, { ...change.item });
else updatedElements.push({ ...change.item });
});
return updatedElements;
}
function applyChange(change, element) {
switch (change.type) {
case "select":
element.selected = change.selected;
break;
case "position":
if (typeof change.position !== "undefined") element.position = change.position;
if (typeof change.dragging !== "undefined") element.dragging = change.dragging;
break;
case "dimensions":
if (typeof change.dimensions !== "undefined") {
element.measured = { ...change.dimensions };
if (change.setAttributes) {
if (change.setAttributes === true || change.setAttributes === "width") element.width = change.dimensions.width;
if (change.setAttributes === true || change.setAttributes === "height") element.height = change.dimensions.height;
}
}
if (typeof change.resizing === "boolean") element.resizing = change.resizing;
break;
}
}
/**
* Drop in function that applies node changes to an array of nodes.
* @public
* @param changes - Array of changes to apply.
* @param nodes - Array of nodes to apply the changes to.
* @returns Array of updated nodes.
* @example
*```tsx
*import { useState, useCallback } from 'react';
*import { ReactFlow, applyNodeChanges, type Node, type Edge, type OnNodesChange } from '@xyflow/react';
*
*export default function Flow() {
* const [nodes, setNodes] = useState([]);
* const [edges, setEdges] = useState([]);
* const onNodesChange: OnNodesChange = useCallback(
* (changes) => {
* setNodes((oldNodes) => applyNodeChanges(changes, oldNodes));
* },
* [setNodes],
* );
*
* return (
*
* );
*}
*```
* @remarks Various events on the component can produce an {@link NodeChange}
* that describes how to update the edges of your flow in some way.
* If you don't need any custom behaviour, this util can be used to take an array
* of these changes and apply them to your edges.
*/
function applyNodeChanges(changes, nodes) {
return applyChanges(changes, nodes);
}
/**
* Drop in function that applies edge changes to an array of edges.
* @public
* @param changes - Array of changes to apply.
* @param edges - Array of edge to apply the changes to.
* @returns Array of updated edges.
* @example
* ```tsx
*import { useState, useCallback } from 'react';
*import { ReactFlow, applyEdgeChanges } from '@xyflow/react';
*
*export default function Flow() {
* const [nodes, setNodes] = useState([]);
* const [edges, setEdges] = useState([]);
* const onEdgesChange = useCallback(
* (changes) => {
* setEdges((oldEdges) => applyEdgeChanges(changes, oldEdges));
* },
* [setEdges],
* );
*
* return (
*
* );
*}
*```
* @remarks Various events on the component can produce an {@link EdgeChange}
* that describes how to update the edges of your flow in some way.
* If you don't need any custom behaviour, this util can be used to take an array
* of these changes and apply them to your edges.
*/
function applyEdgeChanges(changes, edges) {
return applyChanges(changes, edges);
}
function createSelectionChange(id, selected) {
return {
id,
type: "select",
selected
};
}
function getSelectionChanges(items, selectedIds = /* @__PURE__ */ new Set(), mutateItem = false) {
const changes = [];
for (const [id, item] of items) {
const willBeSelected = selectedIds.has(id);
if (!(item.selected === void 0 && !willBeSelected) && item.selected !== willBeSelected) {
if (mutateItem) item.selected = willBeSelected;
changes.push(createSelectionChange(item.id, willBeSelected));
}
}
return changes;
}
function getElementsDiffChanges({ items = [], lookup }) {
const changes = [];
const itemsLookup = new Map(items.map((item) => [item.id, item]));
for (const [index, item] of items.entries()) {
const lookupItem = lookup.get(item.id);
const storeItem = lookupItem?.internals?.userNode ?? lookupItem;
if (storeItem !== void 0 && storeItem !== item) changes.push({
id: item.id,
item,
type: "replace"
});
if (storeItem === void 0) changes.push({
item,
type: "add",
index
});
}
for (const [id] of lookup) if (itemsLookup.get(id) === void 0) changes.push({
id,
type: "remove"
});
return changes;
}
function elementToRemoveChange(item) {
return {
id: item.id,
type: "remove"
};
}
var defaultOnError = createDevWarn("React Flow", "https://reactflow.dev/");
function addEdge(edgeParams, edges, options = {}) {
return addEdge$1(edgeParams, edges, {
...options,
onError: options.onError ?? defaultOnError
});
}
function reconnectEdge(oldEdge, newConnection, edges, options = { shouldReplaceId: true }) {
return reconnectEdge$1(oldEdge, newConnection, edges, {
...options,
onError: options.onError ?? defaultOnError
});
}
/**
* Test whether an object is usable as an [`Node`](/api-reference/types/node).
* In TypeScript this is a type guard that will narrow the type of whatever you pass in to
* [`Node`](/api-reference/types/node) if it returns `true`.
*
* @public
* @remarks In TypeScript this is a type guard that will narrow the type of whatever you pass in to Node if it returns true
* @param element - The element to test.
* @returns Tests whether the provided value can be used as a `Node`. If you're using TypeScript,
* this function acts as a type guard and will narrow the type of the value to `Node` if it returns
* `true`.
*
* @example
* ```js
*import { isNode } from '@xyflow/react';
*
*if (isNode(node)) {
* // ...
*}
*```
*/
var isNode = (element) => isNodeBase(element);
/**
* Test whether an object is usable as an [`Edge`](/api-reference/types/edge).
* In TypeScript this is a type guard that will narrow the type of whatever you pass in to
* [`Edge`](/api-reference/types/edge) if it returns `true`.
*
* @public
* @remarks In TypeScript this is a type guard that will narrow the type of whatever you pass in to Edge if it returns true
* @param element - The element to test
* @returns Tests whether the provided value can be used as an `Edge`. If you're using TypeScript,
* this function acts as a type guard and will narrow the type of the value to `Edge` if it returns
* `true`.
*
* @example
* ```js
*import { isEdge } from '@xyflow/react';
*
*if (isEdge(edge)) {
* // ...
*}
*```
*/
var isEdge = (element) => isEdgeBase(element);
function fixedForwardRef(render) {
return (0, import_react.forwardRef)(render);
}
var useIsomorphicLayoutEffect = typeof window !== "undefined" ? import_react.useLayoutEffect : import_react.useEffect;
/**
* This hook returns a queue that can be used to batch updates.
*
* @param runQueue - a function that gets called when the queue is flushed
* @internal
*
* @returns a Queue object
*/
function useQueue(runQueue) {
const [serial, setSerial] = (0, import_react.useState)(BigInt(0));
const [queue] = (0, import_react.useState)(() => createQueue(() => setSerial((n) => n + BigInt(1))));
useIsomorphicLayoutEffect(() => {
const queueItems = queue.get();
if (queueItems.length) {
runQueue(queueItems);
queue.reset();
}
}, [serial]);
return queue;
}
function createQueue(cb) {
let queue = [];
return {
get: () => queue,
reset: () => {
queue = [];
},
push: (item) => {
queue.push(item);
cb();
}
};
}
var BatchContext = (0, import_react.createContext)(null);
/**
* This is a context provider that holds and processes the node and edge update queues
* that are needed to handle setNodes, addNodes, setEdges and addEdges.
*
* @internal
*/
function BatchProvider({ children }) {
const store = useStoreApi();
const nodeQueue = useQueue((0, import_react.useCallback)((queueItems) => {
const { nodes = [], setNodes, hasDefaultNodes, onNodesChange, nodeLookup, fitViewQueued, onNodesChangeMiddlewareMap } = store.getState();
let next = nodes;
for (const payload of queueItems) next = typeof payload === "function" ? payload(next) : payload;
let changes = getElementsDiffChanges({
items: next,
lookup: nodeLookup
});
for (const middleware of onNodesChangeMiddlewareMap.values()) changes = middleware(changes);
if (hasDefaultNodes) setNodes(next);
if (changes.length > 0) onNodesChange?.(changes);
else if (fitViewQueued) window.requestAnimationFrame(() => {
const { fitViewQueued, nodes, setNodes } = store.getState();
if (fitViewQueued) setNodes(nodes);
});
}, []));
const edgeQueue = useQueue((0, import_react.useCallback)((queueItems) => {
const { edges = [], setEdges, hasDefaultEdges, onEdgesChange, edgeLookup } = store.getState();
let next = edges;
for (const payload of queueItems) next = typeof payload === "function" ? payload(next) : payload;
if (hasDefaultEdges) setEdges(next);
else if (onEdgesChange) onEdgesChange(getElementsDiffChanges({
items: next,
lookup: edgeLookup
}));
}, []));
const value = (0, import_react.useMemo)(() => ({
nodeQueue,
edgeQueue
}), []);
return (0, import_jsx_runtime.jsx)(BatchContext.Provider, {
value,
children
});
}
function useBatchContext() {
const batchContext = (0, import_react.useContext)(BatchContext);
if (!batchContext) throw new Error("useBatchContext must be used within a BatchProvider");
return batchContext;
}
var selector$k = (s) => !!s.panZoom;
/**
* This hook returns a ReactFlowInstance that can be used to update nodes and edges, manipulate the viewport, or query the current state of the flow.
*
* @public
* @example
* ```jsx
*import { useCallback, useState } from 'react';
*import { useReactFlow } from '@xyflow/react';
*
*export function NodeCounter() {
* const reactFlow = useReactFlow();
* const [count, setCount] = useState(0);
* const countNodes = useCallback(() => {
* setCount(reactFlow.getNodes().length);
* // you need to pass it as a dependency if you are using it with useEffect or useCallback
* // because at the first render, it's not initialized yet and some functions might not work.
* }, [reactFlow]);
*
* return (
*
*
* >
* );
* };
* ```
*
* @remarks The `` has no pointer events by default. If you want to
* add mouse interactions you need to set the style `pointerEvents: all` and add
* the `nopan` class on the label or the element you want to interact with.
*/
function EdgeLabelRenderer({ children }) {
const edgeLabelRenderer = useStore(selector$6);
if (!edgeLabelRenderer) return null;
return (0, import_react_dom.createPortal)(children, edgeLabelRenderer);
}
var selector$5 = (s) => s.domNode?.querySelector(".react-flow__viewport-portal");
/**
* The `` component can be used to add components to the same viewport
* of the flow where nodes and edges are rendered. This is useful when you want to render
* your own components that are adhere to the same coordinate system as the nodes & edges
* and are also affected by zooming and panning
* @public
* @example
*
* ```jsx
*import React from 'react';
*import { ViewportPortal } from '@xyflow/react';
*
*export default function () {
* return (
*
*
* This div is positioned at [100, 100] on the flow.
*
*
* );
*}
*```
*/
function ViewportPortal({ children }) {
const viewPortalDiv = useStore(selector$5);
if (!viewPortalDiv) return null;
return (0, import_react_dom.createPortal)(children, viewPortalDiv);
}
/**
* When you programmatically add or remove handles to a node or update a node's
* handle position, you need to let React Flow know about it using this hook. This
* will update the internal dimensions of the node and properly reposition handles
* on the canvas if necessary.
*
* @public
* @returns Use this function to tell React Flow to update the internal state of one or more nodes
* that you have changed programmatically.
*
* @example
* ```jsx
*import { useCallback, useState } from 'react';
*import { Handle, useUpdateNodeInternals } from '@xyflow/react';
*
*export default function RandomHandleNode({ id }) {
* const updateNodeInternals = useUpdateNodeInternals();
* const [handleCount, setHandleCount] = useState(0);
* const randomizeHandleCount = useCallback(() => {
* setHandleCount(Math.floor(Math.random() * 10));
* updateNodeInternals(id);
* }, [id, updateNodeInternals]);
*
* return (
* <>
* {Array.from({ length: handleCount }).map((_, index) => (
*
* ))}
*
*
*
*
There are {handleCount} handles on this node.
*
* >
* );
*}
*```
* @remarks This hook can only be used in a component that is a child of a
*{@link ReactFlowProvider} or a {@link ReactFlow} component.
*/
function useUpdateNodeInternals() {
const store = useStoreApi();
return (0, import_react.useCallback)((id) => {
const { domNode, updateNodeInternals } = store.getState();
const updateIds = Array.isArray(id) ? id : [id];
const updates = /* @__PURE__ */ new Map();
updateIds.forEach((updateId) => {
const nodeElement = domNode?.querySelector(`.react-flow__node[data-id="${updateId}"]`);
if (nodeElement) updates.set(updateId, {
id: updateId,
nodeElement,
force: true
});
});
requestAnimationFrame(() => updateNodeInternals(updates, { triggerFitView: false }));
}, []);
}
var nodesSelector = (state) => state.nodes;
/**
* This hook returns an array of the current nodes. Components that use this hook
* will re-render **whenever any node changes**, including when a node is selected
* or moved.
*
* @public
* @returns An array of all nodes currently in the flow.
*
* @example
* ```jsx
*import { useNodes } from '@xyflow/react';
*
*export default function() {
* const nodes = useNodes();
*
* return
There are currently {nodes.length} nodes!
;
*}
*```
*/
function useNodes() {
return useStore(nodesSelector, shallow$1);
}
var edgesSelector = (state) => state.edges;
/**
* This hook returns an array of the current edges. Components that use this hook
* will re-render **whenever any edge changes**.
*
* @public
* @returns An array of all edges currently in the flow.
*
* @example
* ```tsx
*import { useEdges } from '@xyflow/react';
*
*export default function () {
* const edges = useEdges();
*
* return
There are currently {edges.length} edges!
;
*}
*```
*/
function useEdges() {
return useStore(edgesSelector, shallow$1);
}
var viewportSelector = (state) => ({
x: state.transform[0],
y: state.transform[1],
zoom: state.transform[2]
});
/**
* The `useViewport` hook is a convenient way to read the current state of the
* {@link Viewport} in a component. Components that use this hook
* will re-render **whenever the viewport changes**.
*
* @public
* @returns The current viewport.
*
* @example
*
*```jsx
*import { useViewport } from '@xyflow/react';
*
*export default function ViewportDisplay() {
* const { x, y, zoom } = useViewport();
*
* return (
*
*
* The viewport is currently at ({x}, {y}) and zoomed to {zoom}.
*
*
* );
*}
*```
*
* @remarks This hook can only be used in a component that is a child of a
*{@link ReactFlowProvider} or a {@link ReactFlow} component.
*/
function useViewport() {
return useStore(viewportSelector, shallow$1);
}
/**
* This hook makes it easy to prototype a controlled flow where you manage the
* state of nodes and edges outside the `ReactFlowInstance`. You can think of it
* like React's `useState` hook with an additional helper callback.
*
* @public
* @returns
* - `nodes`: The current array of nodes. You might pass this directly to the `nodes` prop of your
* `` component, or you may want to manipulate it first to perform some layouting,
* for example.
* - `setNodes`: A function that you can use to update the nodes. You can pass it a new array of
* nodes or a callback that receives the current array of nodes and returns a new array of nodes.
* This is the same as the second element of the tuple returned by React's `useState` hook.
* - `onNodesChange`: A handy callback that can take an array of `NodeChanges` and update the nodes
* state accordingly. You'll typically pass this directly to the `onNodesChange` prop of your
* `` component.
* @example
*
*```tsx
*import { ReactFlow, useNodesState, useEdgesState } from '@xyflow/react';
*
*const initialNodes = [];
*const initialEdges = [];
*
*export default function () {
* const [nodes, setNodes, onNodesChange] = useNodesState(initialNodes);
* const [edges, setEdges, onEdgesChange] = useEdgesState(initialEdges);
*
* return (
*
* );
*}
*```
*
* @remarks This hook was created to make prototyping easier and our documentation
* examples clearer. Although it is OK to use this hook in production, in
* practice you may want to use a more sophisticated state management solution
* like Zustand {@link https://reactflow.dev/docs/guides/state-management/} instead.
*
*/
function useNodesState(initialNodes) {
const [nodes, setNodes] = (0, import_react.useState)(initialNodes);
return [
nodes,
setNodes,
(0, import_react.useCallback)((changes) => setNodes((nds) => applyNodeChanges(changes, nds)), [])
];
}
/**
* This hook makes it easy to prototype a controlled flow where you manage the
* state of nodes and edges outside the `ReactFlowInstance`. You can think of it
* like React's `useState` hook with an additional helper callback.
*
* @public
* @returns
* - `edges`: The current array of edges. You might pass this directly to the `edges` prop of your
* `` component, or you may want to manipulate it first to perform some layouting,
* for example.
*
* - `setEdges`: A function that you can use to update the edges. You can pass it a new array of
* edges or a callback that receives the current array of edges and returns a new array of edges.
* This is the same as the second element of the tuple returned by React's `useState` hook.
*
* - `onEdgesChange`: A handy callback that can take an array of `EdgeChanges` and update the edges
* state accordingly. You'll typically pass this directly to the `onEdgesChange` prop of your
* `` component.
* @example
*
*```tsx
*import { ReactFlow, useNodesState, useEdgesState } from '@xyflow/react';
*
*const initialNodes = [];
*const initialEdges = [];
*
*export default function () {
* const [nodes, setNodes, onNodesChange] = useNodesState(initialNodes);
* const [edges, setEdges, onEdgesChange] = useEdgesState(initialEdges);
*
* return (
*
* );
*}
*```
*
* @remarks This hook was created to make prototyping easier and our documentation
* examples clearer. Although it is OK to use this hook in production, in
* practice you may want to use a more sophisticated state management solution
* like Zustand {@link https://reactflow.dev/docs/guides/state-management/} instead.
*
*/
function useEdgesState(initialEdges) {
const [edges, setEdges] = (0, import_react.useState)(initialEdges);
return [
edges,
setEdges,
(0, import_react.useCallback)((changes) => setEdges((eds) => applyEdgeChanges(changes, eds)), [])
];
}
/**
* The `useOnViewportChange` hook lets you listen for changes to the viewport such
* as panning and zooming. You can provide a callback for each phase of a viewport
* change: `onStart`, `onChange`, and `onEnd`.
*
* @public
* @example
* ```jsx
*import { useCallback } from 'react';
*import { useOnViewportChange } from '@xyflow/react';
*
*function ViewportChangeLogger() {
* useOnViewportChange({
* onStart: (viewport: Viewport) => console.log('start', viewport),
* onChange: (viewport: Viewport) => console.log('change', viewport),
* onEnd: (viewport: Viewport) => console.log('end', viewport),
* });
*
* return null;
*}
*```
*/
function useOnViewportChange({ onStart, onChange, onEnd }) {
const store = useStoreApi();
(0, import_react.useEffect)(() => {
store.setState({ onViewportChangeStart: onStart });
}, [onStart]);
(0, import_react.useEffect)(() => {
store.setState({ onViewportChange: onChange });
}, [onChange]);
(0, import_react.useEffect)(() => {
store.setState({ onViewportChangeEnd: onEnd });
}, [onEnd]);
}
/**
* This hook lets you listen for changes to both node and edge selection. As the
*name implies, the callback you provide will be called whenever the selection of
*_either_ nodes or edges changes.
*
* @public
* @example
* ```jsx
*import { useState } from 'react';
*import { ReactFlow, useOnSelectionChange } from '@xyflow/react';
*
*function SelectionDisplay() {
* const [selectedNodes, setSelectedNodes] = useState([]);
* const [selectedEdges, setSelectedEdges] = useState([]);
*
* // the passed handler has to be memoized, otherwise the hook will not work correctly
* const onChange = useCallback(({ nodes, edges }) => {
* setSelectedNodes(nodes.map((node) => node.id));
* setSelectedEdges(edges.map((edge) => edge.id));
* }, []);
*
* useOnSelectionChange({
* onChange,
* });
*
* return (
*
*
Selected nodes: {selectedNodes.join(', ')}
*
Selected edges: {selectedEdges.join(', ')}
*
* );
*}
*```
*
* @remarks You need to memoize the passed `onChange` handler, otherwise the hook will not work correctly.
*/
function useOnSelectionChange({ onChange }) {
const store = useStoreApi();
(0, import_react.useEffect)(() => {
const nextOnSelectionChangeHandlers = [...store.getState().onSelectionChangeHandlers, onChange];
store.setState({ onSelectionChangeHandlers: nextOnSelectionChangeHandlers });
return () => {
const nextHandlers = store.getState().onSelectionChangeHandlers.filter((fn) => fn !== onChange);
store.setState({ onSelectionChangeHandlers: nextHandlers });
};
}, [onChange]);
}
var selector$4 = (options) => (s) => {
if (!options.includeHiddenNodes) return s.nodesInitialized;
if (s.nodeLookup.size === 0) return false;
for (const [, { internals }] of s.nodeLookup) if (internals.handleBounds === void 0 || !nodeHasDimensions(internals.userNode)) return false;
return true;
};
/**
* This hook tells you whether all the nodes in a flow have been measured and given
*a width and height. When you add a node to the flow, this hook will return
*`false` and then `true` again once the node has been measured.
*
* @public
* @returns Whether or not the nodes have been initialized by the `` component and
* given a width and height.
*
* @example
* ```jsx
*import { useReactFlow, useNodesInitialized } from '@xyflow/react';
*import { useEffect, useState } from 'react';
*
*const options = {
* includeHiddenNodes: false,
*};
*
*export default function useLayout() {
* const { getNodes } = useReactFlow();
* const nodesInitialized = useNodesInitialized(options);
* const [layoutedNodes, setLayoutedNodes] = useState(getNodes());
*
* useEffect(() => {
* if (nodesInitialized) {
* setLayoutedNodes(yourLayoutingFunction(getNodes()));
* }
* }, [nodesInitialized]);
*
* return layoutedNodes;
*}
*```
*/
function useNodesInitialized(options = { includeHiddenNodes: false }) {
return useStore(selector$4(options));
}
/**
* Hook to check if a is connected to another and get the connections.
*
* @public
* @deprecated Use `useNodeConnections` instead.
* @returns An array with handle connections.
*/
function useHandleConnections({ type, id, nodeId, onConnect, onDisconnect }) {
console.warn("[DEPRECATED] `useHandleConnections` is deprecated. Instead use `useNodeConnections` https://reactflow.dev/api-reference/hooks/useNodeConnections");
const _nodeId = useNodeId();
const currentNodeId = nodeId ?? _nodeId;
const prevConnections = (0, import_react.useRef)(null);
const connections = useStore((state) => state.connectionLookup.get(`${currentNodeId}-${type}${id ? `-${id}` : ""}`), areConnectionMapsEqual);
(0, import_react.useEffect)(() => {
if (prevConnections.current && prevConnections.current !== connections) {
const _connections = connections ?? /* @__PURE__ */ new Map();
handleConnectionChange(prevConnections.current, _connections, onDisconnect);
handleConnectionChange(_connections, prevConnections.current, onConnect);
}
prevConnections.current = connections ?? /* @__PURE__ */ new Map();
}, [
connections,
onConnect,
onDisconnect
]);
return (0, import_react.useMemo)(() => Array.from(connections?.values() ?? []), [connections]);
}
var error014 = errorMessages["error014"]();
/**
* This hook returns an array of connections on a specific node, handle type ('source', 'target') or handle ID.
*
* @public
* @returns An array with connections.
*
* @example
* ```jsx
*import { useNodeConnections } from '@xyflow/react';
*
*export default function () {
* const connections = useNodeConnections({
* handleType: 'target',
* handleId: 'my-handle',
* });
*
* return (
*
There are currently {connections.length} incoming connections!
* );
*}
*```
*/
function useNodeConnections({ id, handleType, handleId, onConnect, onDisconnect } = {}) {
const nodeId = useNodeId();
const currentNodeId = id ?? nodeId;
if (!currentNodeId) throw new Error(error014);
const prevConnections = (0, import_react.useRef)(null);
const connections = useStore((state) => state.connectionLookup.get(`${currentNodeId}${handleType ? handleId ? `-${handleType}-${handleId}` : `-${handleType}` : ""}`), areConnectionMapsEqual);
(0, import_react.useEffect)(() => {
if (prevConnections.current && prevConnections.current !== connections) {
const _connections = connections ?? /* @__PURE__ */ new Map();
handleConnectionChange(prevConnections.current, _connections, onDisconnect);
handleConnectionChange(_connections, prevConnections.current, onConnect);
}
prevConnections.current = connections ?? /* @__PURE__ */ new Map();
}, [
connections,
onConnect,
onDisconnect
]);
return (0, import_react.useMemo)(() => Array.from(connections?.values() ?? []), [connections]);
}
function useNodesData(nodeIds) {
return useStore((0, import_react.useCallback)((s) => {
const data = [];
const isArrayOfIds = Array.isArray(nodeIds);
const _nodeIds = isArrayOfIds ? nodeIds : [nodeIds];
for (const nodeId of _nodeIds) {
const node = s.nodeLookup.get(nodeId);
if (node) data.push({
id: node.id,
type: node.type,
data: node.data
});
}
return isArrayOfIds ? data : data[0] ?? null;
}, [nodeIds]), shallowNodeData);
}
/**
* This hook returns the internal representation of a specific node.
* Components that use this hook will re-render **whenever the node changes**,
* including when a node is selected or moved.
*
* @public
* @param id - The ID of a node you want to observe.
* @returns The `InternalNode` object for the node with the given ID.
*
* @example
* ```tsx
*import { useInternalNode } from '@xyflow/react';
*
*export default function () {
* const internalNode = useInternalNode('node-1');
* const absolutePosition = internalNode.internals.positionAbsolute;
*
* return (
*