UNPKG

@linkurious/ogma-react

Version:

A light adaptation of Ogma for React application

744 lines (743 loc) 20.3 kB
import H, { createContext as Q, useContext as X, memo as V, forwardRef as S, useRef as U, useState as y, useImperativeHandle as C, useEffect as a, useLayoutEffect as p, useCallback as ee } from "react"; import { Ogma as te, Node as j, Edge as J } from "@linkurious/ogma"; import { renderToString as F } from "react-dom/server"; import { createPortal as G } from "react-dom"; const K = Q(null), w = () => { const e = X(K); if (!e) throw new Error("useOgma must be used within an OgmaProvider"); return e.ogma; }; function z(e, n) { Object.keys(e).forEach((t) => { const o = e[t]; o && n(t, o); }); } function ne(e) { return e.startsWith("on") && e.length > 2 ? e[2].toLowerCase() + e.substring(3) : null; } function I(e, n, t) { const o = {}; Object.keys(n).forEach((i) => { if (!i.startsWith("on")) return; const r = ne(i), f = n[i]; r && typeof f == "function" && (o[r] = f); }), z(t, (i, s) => { o[i] || (e.events.off(s), delete t[i]); }), z(o, (i, s) => { const r = t[i]; r && r !== s && e.events.off(r), (!r || r !== s) && (e.events.on(i, s), t[i] = s); }); } function R(e, n) { if (e === n) return !0; try { return JSON.stringify(e) === JSON.stringify(n); } catch { return !1; } } const _ = {}, oe = (e, n) => { const { options: t = _, children: o, graph: i, onReady: s, theme: r, className: f = "ogma-container" } = e, d = U({}), c = U(null), [m, P] = y(), [k, u] = y(), [T, h] = y(_), [L, b] = y(); return C(n, () => m, [m]), a(() => { if (!c.current || m) return; const g = new te({ container: c.current, graph: i, options: t }); u(i), h(t), r && (b(r), g.styles.setTheme(r)), I(g, e, d.current), P(g), s && s(g); }, [c.current]), p(() => { const g = () => m?.view.forceResize(); return g(), window.addEventListener("resize", g), () => window.removeEventListener("resize", g); }, []), a(() => { m && (i && R(i, k) === !1 && (u(i), m.setGraph(i)), t && R(t, T) === !1 && (h(t), m.setOptions(t))); }, [i, t]), a(() => { m && r && R(r, L) === !1 && (b(r), m.styles.setTheme(r)); }, [r]), a(() => { m && I(m, e, d.current); }, [e]), /* @__PURE__ */ H.createElement( "div", { style: { width: "100%", height: "100%" }, className: f, ref: c }, m && /* @__PURE__ */ H.createElement( K.Provider, { value: { ogma: m } }, o ) ); }, ze = V(S(oe)); function Ie(e, n, t) { return ee(n, t || []); } const se = S( ({ selector: e, attributes: n }, t) => { const o = w(), [i, s] = y(); return C(t, () => i, [i]), a(() => { const r = e ? o.styles.addNodeRule(e, n) : o.styles.addNodeRule(n); return s(r), () => { r.destroy(), s(void 0); }; }, [e, n]), null; } ), ie = ({ attributes: e, fullOverwrite: n }) => { const t = w(); return a(() => (t.styles.setHoveredNodeAttributes(e, n), () => { t.styles.setHoveredNodeAttributes(null); }), [e, n]), null; }, re = ({ attributes: e, fullOverwrite: n }) => { const t = w(); return a(() => (t.styles.setSelectedNodeAttributes(e, n), () => { t.styles.setSelectedNodeAttributes(null); }), [e, n]), null; }, _e = Object.assign( se, { Hovered: ie, Selected: re } ), ae = S( ({ selector: e, attributes: n }, t) => { const o = w(), [i, s] = y(); return C(t, () => i, [i]), a(() => { const r = e ? o.styles.addEdgeRule(e, n) : o.styles.addEdgeRule(n); return s(r), () => { r.destroy(), s(void 0); }; }, [e, n]), null; } ), le = ({ attributes: e, fullOverwrite: n }) => { const t = w(); return a(() => (t.styles.setHoveredEdgeAttributes(e, n), () => { t.styles.setHoveredEdgeAttributes(null); }), [e, n]), null; }, de = ({ attributes: e, fullOverwrite: n }) => { const t = w(); return a(() => (t.styles.setSelectedEdgeAttributes(e, n), () => { t.styles.setSelectedEdgeAttributes(null); }), [e, n]), null; }, qe = Object.assign( ae, { Hovered: le, Selected: de } ), ce = S(({ name: e, edgeAttributes: n, edgeDependencies: t, edgeOutput: o, nodeAttributes: i, nodeDependencies: s, nodeOutput: r }, f) => { const d = w(), [c, m] = y( null ); return C(f, () => c, [ c ]), a(() => { const P = { edgeAttributes: n, edgeDependencies: t, edgeOutput: o, nodeAttributes: i, nodeDependencies: s, nodeOutput: r }; async function k() { const u = d.styles.createClass({ name: e, ...P }); await d.view.afterNextFrame(), m(u); } return k(), () => { async function u() { const T = d.styles.getClass(e); T && await T.destroy(), m(null); } u(); }; }, []), a(() => { c && c.update({ edgeAttributes: n, edgeDependencies: t, edgeOutput: o, nodeAttributes: i, nodeDependencies: s, nodeOutput: r }); }, [ n, t, o, i, s, r ]), null; }), ue = (e, n) => e.name === n.name && e.edgeAttributes === n.edgeAttributes && e.edgeDependencies === n.edgeDependencies && e.edgeOutput === n.edgeOutput && e.nodeAttributes === n.nodeAttributes && e.nodeDependencies === n.nodeDependencies && e.nodeOutput === n.nodeOutput, Me = V(ce, ue); function fe(e, n) { const t = w(), [o, i] = y(null); return C(n, () => o, [o]), a(() => { const { disabled: s, ...r } = e, f = t.transformations.addDrillDown({ ...r, enabled: !s }); return i(f), () => { f.destroy(), i(null); }; }, []), a(() => { if (o) { const s = !!e.disabled, r = e.duration; s ? o.disable(r) : o.enable(r); } }, [e.disabled]), a(() => { const { disabled: s, ...r } = e; o?.setOptions(r); }, [ e.copyData, e.depthPath, e.duration, e.easing, e.nodeGenerator, e.onDestroyed, e.onDisabled, e.onEnabled, e.onGetSubgraph, e.onGroupUpdate, e.onSetIndex, e.onUpdated, e.padding, e.parentPath, e.showContents ]), null; } const Be = S( fe ); function x(e, n, t) { n === e.isEnabled() && (n ? e.disable(t) : e.enable(t)); } function N(e, n, t) { const o = ({ target: c }) => { c === n && e.onEnabled && e.onEnabled(n); }, i = ({ target: c }) => { c === n && e.onDisabled && e.onDisabled(n); }, s = ({ target: c }) => { c === n && e.onUpdated && e.onUpdated(n); }, r = ({ target: c, index: m }) => { c === n && e.onSetIndex && e.onSetIndex(n, m); }, f = ({ target: c }) => { c === n && (e.onDestroyed && e.onDestroyed(n), t.events.off(o).off(i).off(s).off(r).off(f)); }; return t.events.on("transformationEnabled", o).on("transformationDisabled", i).on("transformationDestroyed", f).on("transformationSetIndex", r).on("transformationRefresh", s), () => { t.events.off(o).off(i).off(s).off(r).off(f); }; } function ge(e, n) { const t = w(), [o, i] = y(); return C(n, () => o, [o]), a(() => { const s = t.transformations.addNodeGrouping({ ...e, enabled: !e.disabled }); return N(e, s, t), i(s), () => { s.destroy(), i(void 0); }; }, []), a(() => { o && x(o, !!e.disabled, e.duration); }, [e.disabled, e.duration]), a(() => { o?.setOptions(e); }, [ e.groupIdFunction, e.groupSelfLoopEdges, e.edgeGenerator, e.nodeGenerator, e.groupEdges, e.padding, e.selector, e.showContents, e.separateEdgesByDirection ]), null; } const Ze = S(ge); function me(e, n) { const t = w(), [o, i] = y(); return C(n, () => o, [o]), a(() => { const s = t.transformations.addEdgeGrouping({ ...e, enabled: !e.disabled }); return N(e, s, t), i(s), () => { s.destroy(), i(void 0); }; }, []), a(() => { o && x(o, !!e.disabled, e.duration); }, [e.disabled, e.duration]), a(() => { o?.setOptions(e); }, [ e.selector, e.generator, e.groupIdFunction, e.separateEdgesByDirection ]), null; } const Ve = S(me); function ye(e, n) { const t = w(), [o, i] = y(); return C(n, () => o, [o]), a(() => { const s = t.transformations.addNodeCollapsing({ ...e, enabled: !e.disabled }); return N(e, s, t), i(s), () => { s.destroy(), i(void 0); }; }, []), a(() => { o && x(o, !!e.disabled, e.duration); }, [e.disabled, e.duration]), a(() => { o?.setOptions(e); }, [e.edgeGenerator, e.selector]), null; } const je = S(ye); function he(e, n) { const t = w(), [o, i] = y(); return C(n, () => o, [o]), a(() => { const s = t.transformations.addNeighborMerging({ ...e, enabled: !e.disabled }); return N(e, s, t), i(s), () => { s.destroy(), i(void 0); }; }, []), a(() => { o && x(o, !!e.disabled, e.duration); }, [e.disabled, e.duration]), a(() => { o?.setOptions(e); }, [e.dataFunction, e.selector]), null; } const Je = S(he); function be(e, n) { const t = w(), [o, i] = y(); return C(n, () => o, [o]), a(() => { const s = t.transformations.addNeighborGeneration({ ...e, enabled: !e.disabled }); return N(e, s, t), i(s), () => { s.destroy(), i(void 0); }; }, []), a(() => { o && x(o, !!e.disabled, e.duration); }, [e.disabled, e.duration]), a(() => { o?.setOptions(e); }, [ e.edgeGenerator, e.nodeGenerator, e.neighborIdFunction, e.selector ]), null; } const Ke = S(be); function Ee(e, n) { const t = w(), [o, i] = y(); return C(n, () => o, [o]), a(() => { const s = t.transformations.addEdgeFilter({ ...e, enabled: !e.disabled }); return N(e, s, t), i(s), () => { s.destroy(), i(void 0); }; }, []), a(() => { o && x(o, !!e.disabled, e.duration); }, [e.disabled]), a(() => { o?.setOptions(e); }, [e.criteria]), null; } const Ye = S(Ee); function we(e, n) { const t = w(), [o, i] = y(); return C(n, () => o, [o]), a(() => { const s = t.transformations.addNodeFilter({ ...e, enabled: !e.disabled }); return N(e, s, t), i(s), () => { s.destroy(), i(void 0); }; }, []), a(() => { o && x(o, !!e.disabled, e.duration); }, [e.disabled]), a(() => { o?.setOptions(e); }, [e.criteria]), null; } const Qe = S(we); function Se(e, n, t, o) { return typeof t == "string" ? t : typeof t == "function" ? F(t(e, n)) : F(o); } function D(e, n) { return typeof e == "function" ? e(n) : e; } const q = (e, n) => `${e} ${e}--${n}`; function Ce(e = "&times;", n) { if (e) { const t = typeof e == "string" ? e : F(e); return `<div class=${n}>${t}</div>`; } return ""; } function Te(e) { return e.endsWith("Doubleclick") ? "doubleclick" : e.toLowerCase().endsWith("click") ? "click" : "mouseover"; } function ve(e, n) { if (e instanceof j) { const t = e.getAttribute("radius"), o = M("outer", e, n), i = M("inner", e, n); return t + o + i; } else if (e instanceof J) return e.size; return 0; } function M(e, n, t) { const o = n.getAttribute( `${e}Stroke.width` ); return n.getAttribute(`${e}Stroke.minVisibleSize`) > n.size ? 0 : n.getAttribute(`${e}Stroke.scalingMethod`) === "fixed" ? o : o / t; } function B(e, n, t) { const o = ve(e, n), i = { x: 0, y: 0 }; switch (t) { case "top": i.y = -o; break; case "bottom": i.y = o; break; case "left": i.x = -o; break; case "right": i.x = o; break; } return i; } function Oe(e, n, t) { return e.left < 0 ? "right" : e.right > n ? "left" : e.top < 0 ? "bottom" : e.bottom > t ? "top" : null; } function Z(e, n, t) { switch (e || n) { case "top": return `translate(calc(-50% + ${t.x}px),calc(-100% + ${t.y}px))`; case "bottom": return `translate(calc(-50% + ${t.x}px),${t.y}px)`; case "left": return `translate(calc(-100% + ${t.x}px),calc(-50% + ${t.y}px))`; default: return `translate(${t.x}px,calc(-50% + ${t.y}px))`; } } const W = { x: -9999, y: -9999 }, Pe = "ogma-popup--content", Le = "ogma-popup--close", ke = "ogma-popup--body", $e = "ogma-popup", xe = ({ content: e, position: n, children: t, isOpen: o = !0, closeButton: i, onClose: s = () => { }, placement: r = "top", popupClass: f = $e, closeButtonClass: d = Le, contentClass: c = Pe, popupBodyClass: m = ke, size: P, closeOnEsc: k = !0 }, u) => { const T = w(), [h, L] = y(null); if (C(u, () => h, [h]), a(() => { let g = null, v = null, l = null; if (o) { const E = D(n, T) || W; if (g = T.layers.addOverlay({ position: E || W, element: `<div class="${q(f, r)}"/> <div class="${m}"> ${Ce(i, d)} <div class="${c} "></div> </div> </div>`, size: P || { width: "auto", height: "auto" }, scaled: !1 }), l = (O) => { const $ = g?.element.querySelector( `.${d}` ); O.target && $.contains(O.target) && (O.stopPropagation(), O.preventDefault(), s()); }, v = ({ code: O }) => { O === 27 && s(); }, k && T.events.on("keyup", v), g.element.addEventListener("click", l), L(g), e && !t) { const O = g.element.querySelector( `.${c}` ), $ = Se(T, E, e, t); O && (O.innerHTML = $); } L(g); } return () => { g && (l && g.element.removeEventListener("click", l), v && T.events.off(v), g.destroy(), L(null)); }; }, [o, T]), a(() => { if (h && h.element) { const g = D(n, T) || W; if (h.setPosition(g), h.element.className = q(f, r), e && !t) { const v = h.element.querySelector(`.${c}`); v && (v.innerHTML = typeof e == "string" ? e : ""); } o ? h.show() : h.hide(); } }, [h, n, o, r, f, e, t]), !h || !o) return null; const b = h.element.querySelector(`.${c}`); return b && t ? G(t, b) : null; }, Xe = S(xe), Ne = { x: -9999, y: -9999 }, Ge = ({ eventName: e, position: n, children: t, placement: o = "top", bodyClass: i = "ogma-tooltip--body", translate: s = { x: 0, y: 0 }, size: r }, f) => { const d = w(), [c, m] = y(), [P, k] = y(), [u, T] = y(null); C(f, () => u, [u]); function h(b, g) { if (n) u?.show(); else { const E = d.geo.enabled() ? d.geo.getZoom() : d.view.getZoom(), O = B(b, E, o), $ = { x: g.x + O.x, y: g.y + O.y }; k(g), u?.setPosition($); } const v = Z(null, o, s), l = u.element.children[0]; l.style.transform = v; } function L() { u?.hide(), m(void 0); } if (a(() => { const b = d.layers.addOverlay({ position: n || Ne, element: ` <div style="pointer-events: none"> <div class="${i}" style="pointer-events: auto"> </div> </div>`, size: r || { width: "auto", height: "auto" }, scaled: !1 }); T(b); }, []), a(() => { if (!u) return; let b = () => null, g = () => null; const v = Te(e); return v === "mouseover" ? (b = (l) => { if (e.startsWith("node")) { if (l.target?.isNode) { const E = l.target; m(E), h(E, E.getPosition()); } } else if (e.startsWith("edge") && l.target && !l.target.isNode) { const E = d.view.screenToGraphCoordinates({ x: l.x, y: l.y }); m(l.target), h(l.target, E); } }, g = (l) => { (e.startsWith("node") && l.target?.isNode || e.startsWith("edge") && l.target && !l.target.isNode) && L(); }, d.events.on("mouseout", g)) : (b = (l) => { if (!(e.endsWith("Rightclick") && l.button === "left")) { if (e.startsWith("background")) { if (!l.target) { const E = d.view.screenToGraphCoordinates({ x: l.x, y: l.y }); m(E), h("background", E); } } else if (e.startsWith("node")) { if (l.target?.isNode) { const E = l.target; m(E), h(E, E.getPosition()); } } else if (l.target && !l.target.isNode) { const E = d.view.screenToGraphCoordinates({ x: l.x, y: l.y }); m(l.target), h(l.target, E); } } }, g = (l) => { e.startsWith("node") ? l.target?.isNode || L() : e.startsWith("edge") ? (!l.target || l.target.isNode) && L() : e.startsWith("background") && (l.target || e.endsWith("Rightclick") && l.button === "left" || e.endsWith("Click") && l.button === "right") && L(); }, d.events.on("click", g)), u.hide(), d.events.on(v, b), () => { d.events.off(b), d.events.off(g), u && (u.destroy(), T(null)); }; }, [u]), a(() => { !u || !u.element || (n && u.setPosition(n), (o || i) && (u.element.firstElementChild.className = "ogma-popup--body " + i), r && u.setSize(r)); }, [n, o, r, i]), a(() => { if (!u || !u.element || !c) return; const b = u.element, g = b.children[0].getBoundingClientRect(), v = b.ownerDocument.defaultView, l = Oe( g, v.innerWidth, v.innerHeight ); if (l) { const E = d.geo.enabled() ? d.geo.getZoom() : d.view.getZoom(), O = c instanceof j || c instanceof J ? c : "background", $ = B(O, E, l); u?.setPosition({ x: P.x + $.x, y: P.y + $.y }); const Y = Z(l, o, s); b.children[0].style.transform = Y; } u.show(); }, [P]), !u || !u.element) return null; if (t instanceof Function) { if (!c) return null; const b = t(c); return b === null ? (u.hide(), null) : G(b, u.element.firstElementChild); } else return t ? G(t, u.element.firstElementChild) : null; }, pe = S(Ge), De = ({ noClear: e = !1, isStatic: n = !1, render: t, index: o, visible: i = !0 }, s) => { const r = w(), [f, d] = y(null); return C(s, () => f, [f]), a(() => { const c = r.layers.addCanvasLayer( t, { isStatic: n, noClear: e }, o ); return d(c), () => { c && (c.destroy(), d(null)); }; }, []), a(() => { f && (o !== void 0 && isFinite(o) && f.moveTo(o), i ? f.show() : f.hide()); }, [f, o, i]), null; }, et = S(De), A = { x: -9999, y: -9999 }, Re = S( ({ position: e, children: n, className: t = "", size: o, scaled: i, index: s }, r) => { const f = w(), [d, c] = y(null); return C(r, () => d, [d]), a(() => { const m = D(e, f) || A, P = document.createElement("div"); P.className = t; const k = f.layers.addOverlay( { position: m || A, element: P, size: o || { width: "auto", height: "auto" }, scaled: i }, s ); return c(k), () => { d && (d.destroy(), c(null)); }; }, []), a(() => { if (d) { const m = D(e, f) || A; t && (d.element.className = t), s !== void 0 && isFinite(s) && d.moveTo(s), d.setPosition(m); } }, [e, t, s]), d ? G(n, d.element) : null; } ), tt = Re, We = S( ({ children: e, className: n = "", index: t }, o) => { const i = w(), [s, r] = y(null); return C(o, () => s, [s]), a(() => { const f = document.createElement("div"); f.className = n; const d = i.layers.addLayer(f, t); return r(d), () => { s && (s.destroy(), r(null)); }; }, []), a(() => { s && (n && (s.element.className = n), t !== void 0 && isFinite(t) && s.moveTo(t)); }, [n, t]), s ? G(e, s.element) : null; } ), nt = We; function ot({ enabled: e = !1, ...n }) { const t = w(); return a(() => { e ? t.geo.enable(n) : t.geo.disable(); }, [e]), null; } export { et as CanvasLayer, Ye as EdgeFilter, Ve as EdgeGrouping, qe as EdgeStyle, qe as EdgeStyleRule, ot as Geo, nt as Layer, Ke as NeighborGeneration, Je as NeighborMerging, je as NodeCollapsing, ye as NodeCollapsingComponent, Be as NodeDrilldown, Qe as NodeFilter, Ze as NodeGrouping, _e as NodeStyle, _e as NodeStyleRule, ze as Ogma, tt as Overlay, Xe as Popup, Me as StyleClass, pe as Tooltip, z as forEachEventHandler, ne as getEventNameFromProp, Ie as useEvent, w as useOgma }; //# sourceMappingURL=index.mjs.map