mirror of
https://github.com/ae-utbm/sith.git
synced 2026-10-02 08:54:18 +00:00
Move family_graph.js to webpack
* Remove cytoscape dependencies
This commit is contained in:
1 parent
ceee393bd8
commit
09081b03b6
12 files changed
+308
-344
No files matched your search
@@ -1,274 +0,0 @@
|
||||
async function getGraphData(url, godfathersDepth, godchildrenDepth) {
|
||||
const data = await (
|
||||
await fetch(
|
||||
`${url}?godfathers_depth=${godfathersDepth}&godchildren_depth=${godchildrenDepth}`,
|
||||
)
|
||||
).json();
|
||||
return [
|
||||
...data.users.map((user) => {
|
||||
return { data: user };
|
||||
}),
|
||||
...data.relationships.map((rel) => {
|
||||
return {
|
||||
data: { source: rel.godfather, target: rel.godchild },
|
||||
};
|
||||
}),
|
||||
];
|
||||
}
|
||||
|
||||
function createGraph(container, data, activeUserId) {
|
||||
// biome-ignore lint/correctness/noUndeclaredVariables: imported by user_godphaters_tree.jinja
|
||||
const cy = cytoscape({
|
||||
boxSelectionEnabled: false,
|
||||
autounselectify: true,
|
||||
|
||||
container,
|
||||
elements: data,
|
||||
minZoom: 0.5,
|
||||
|
||||
style: [
|
||||
// the stylesheet for the graph
|
||||
{
|
||||
selector: "node",
|
||||
style: {
|
||||
label: "data(display_name)",
|
||||
"background-image": "data(profile_pict)",
|
||||
width: "100%",
|
||||
height: "100%",
|
||||
"background-fit": "cover",
|
||||
"background-repeat": "no-repeat",
|
||||
shape: "ellipse",
|
||||
},
|
||||
},
|
||||
|
||||
{
|
||||
selector: "edge",
|
||||
style: {
|
||||
width: 5,
|
||||
"line-color": "#ccc",
|
||||
"target-arrow-color": "#ccc",
|
||||
"target-arrow-shape": "triangle",
|
||||
"curve-style": "bezier",
|
||||
},
|
||||
},
|
||||
|
||||
{
|
||||
selector: ".traversed",
|
||||
style: {
|
||||
"border-width": "5px",
|
||||
"border-style": "solid",
|
||||
"border-color": "red",
|
||||
"target-arrow-color": "red",
|
||||
"line-color": "red",
|
||||
},
|
||||
},
|
||||
|
||||
{
|
||||
selector: ".not-traversed",
|
||||
style: {
|
||||
"line-opacity": "0.5",
|
||||
"background-opacity": "0.5",
|
||||
"background-image-opacity": "0.5",
|
||||
},
|
||||
},
|
||||
],
|
||||
layout: {
|
||||
name: "klay",
|
||||
nodeDimensionsIncludeLabels: true,
|
||||
fit: true,
|
||||
klay: {
|
||||
addUnnecessaryBendpoints: true,
|
||||
direction: "DOWN",
|
||||
nodePlacement: "INTERACTIVE",
|
||||
layoutHierarchy: true,
|
||||
},
|
||||
},
|
||||
});
|
||||
const activeUser = cy.getElementById(activeUserId).style("shape", "rectangle");
|
||||
/* Reset graph */
|
||||
const resetGraph = () => {
|
||||
cy.elements((element) => {
|
||||
if (element.hasClass("traversed")) {
|
||||
element.removeClass("traversed");
|
||||
}
|
||||
if (element.hasClass("not-traversed")) {
|
||||
element.removeClass("not-traversed");
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
const onNodeTap = (el) => {
|
||||
resetGraph();
|
||||
/* Create path on graph if selected isn't the targeted user */
|
||||
if (el === activeUser) {
|
||||
return;
|
||||
}
|
||||
cy.elements((element) => {
|
||||
element.addClass("not-traversed");
|
||||
});
|
||||
|
||||
for (const traversed of cy.elements().aStar({
|
||||
root: el,
|
||||
goal: activeUser,
|
||||
}).path) {
|
||||
traversed.removeClass("not-traversed");
|
||||
traversed.addClass("traversed");
|
||||
}
|
||||
};
|
||||
|
||||
cy.on("tap", "node", (tapped) => {
|
||||
onNodeTap(tapped.target);
|
||||
});
|
||||
cy.zoomingEnabled(false);
|
||||
|
||||
/* Add context menu */
|
||||
if (cy.cxtmenu === undefined) {
|
||||
throw new Error("ctxmenu isn't loaded, context menu won't be available on graphs");
|
||||
}
|
||||
cy.cxtmenu({
|
||||
selector: "node",
|
||||
|
||||
commands: [
|
||||
{
|
||||
content: '<i class="fa fa-external-link fa-2x"></i>',
|
||||
select: (el) => {
|
||||
window.open(el.data().profile_url, "_blank").focus();
|
||||
},
|
||||
},
|
||||
|
||||
{
|
||||
content: '<span class="fa fa-mouse-pointer fa-2x"></span>',
|
||||
select: (el) => {
|
||||
onNodeTap(el);
|
||||
},
|
||||
},
|
||||
|
||||
{
|
||||
content: '<i class="fa fa-eraser fa-2x"></i>',
|
||||
select: (_) => {
|
||||
resetGraph();
|
||||
},
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
return cy;
|
||||
}
|
||||
|
||||
document.addEventListener("alpine:init", () => {
|
||||
/*
|
||||
This needs some constants to be set before the document has been loaded
|
||||
|
||||
apiUrl: base url for fetching the tree as a string
|
||||
activeUser: id of the user to fetch the tree from
|
||||
depthMin: minimum tree depth for godfathers and godchildren as an int
|
||||
depthMax: maximum tree depth for godfathers and godchildren as an int
|
||||
*/
|
||||
const defaultDepth = 2;
|
||||
|
||||
if (
|
||||
// biome-ignore lint/correctness/noUndeclaredVariables: defined by user_godfathers_tree.jinja
|
||||
typeof apiUrl === "undefined" ||
|
||||
// biome-ignore lint/correctness/noUndeclaredVariables: defined by user_godfathers_tree.jinja
|
||||
typeof activeUser === "undefined" ||
|
||||
// biome-ignore lint/correctness/noUndeclaredVariables: defined by user_godfathers_tree.jinja
|
||||
typeof depthMin === "undefined" ||
|
||||
// biome-ignore lint/correctness/noUndeclaredVariables: defined by user_godfathers_tree.jinja
|
||||
typeof depthMax === "undefined"
|
||||
) {
|
||||
throw new Error(
|
||||
"Some constants are not set before using the family_graph script, please look at the documentation",
|
||||
);
|
||||
}
|
||||
|
||||
function getInitialDepth(prop) {
|
||||
// biome-ignore lint/correctness/noUndeclaredVariables: defined by script.js
|
||||
const value = Number.parseInt(initialUrlParams.get(prop));
|
||||
// biome-ignore lint/correctness/noUndeclaredVariables: defined by user_godfathers_tree.jinja
|
||||
if (Number.isNaN(value) || value < depthMin || value > depthMax) {
|
||||
return defaultDepth;
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
Alpine.data("graph", () => ({
|
||||
loading: false,
|
||||
godfathersDepth: getInitialDepth("godfathersDepth"),
|
||||
godchildrenDepth: getInitialDepth("godchildrenDepth"),
|
||||
// biome-ignore lint/correctness/noUndeclaredVariables: defined by script.js
|
||||
reverse: initialUrlParams.get("reverse")?.toLowerCase?.() === "true",
|
||||
graph: undefined,
|
||||
graphData: {},
|
||||
|
||||
async init() {
|
||||
const delayedFetch = Alpine.debounce(async () => {
|
||||
await this.fetchGraphData();
|
||||
}, 100);
|
||||
for (const param of ["godfathersDepth", "godchildrenDepth"]) {
|
||||
this.$watch(param, async (value) => {
|
||||
// biome-ignore lint/correctness/noUndeclaredVariables: defined by user_godfathers_tree.jinja
|
||||
if (value < depthMin || value > depthMax) {
|
||||
return;
|
||||
}
|
||||
// biome-ignore lint/correctness/noUndeclaredVariables: defined by script.js
|
||||
updateQueryString(param, value, History.REPLACE);
|
||||
await delayedFetch();
|
||||
});
|
||||
}
|
||||
this.$watch("reverse", async (value) => {
|
||||
// biome-ignore lint/correctness/noUndeclaredVariables: defined by script.js
|
||||
updateQueryString("reverse", value, History.REPLACE);
|
||||
await this.reverseGraph();
|
||||
});
|
||||
this.$watch("graphData", async () => {
|
||||
await this.generateGraph();
|
||||
if (this.reverse) {
|
||||
await this.reverseGraph();
|
||||
}
|
||||
});
|
||||
await this.fetchGraphData();
|
||||
},
|
||||
|
||||
screenshot() {
|
||||
const link = document.createElement("a");
|
||||
link.href = this.graph.jpg();
|
||||
link.download = interpolate(
|
||||
gettext("family_tree.%(extension)s"),
|
||||
{ extension: "jpg" },
|
||||
true,
|
||||
);
|
||||
document.body.appendChild(link);
|
||||
link.click();
|
||||
document.body.removeChild(link);
|
||||
},
|
||||
|
||||
reset() {
|
||||
this.reverse = false;
|
||||
this.godfathersDepth = defaultDepth;
|
||||
this.godchildrenDepth = defaultDepth;
|
||||
},
|
||||
|
||||
async reverseGraph() {
|
||||
this.graph.elements((el) => {
|
||||
el.position({ x: -el.position().x, y: -el.position().y });
|
||||
});
|
||||
this.graph.center(this.graph.elements());
|
||||
},
|
||||
|
||||
async fetchGraphData() {
|
||||
this.graphData = await getGraphData(
|
||||
// biome-ignore lint/correctness/noUndeclaredVariables: defined by user_godfathers_tree.jinja
|
||||
apiUrl,
|
||||
this.godfathersDepth,
|
||||
this.godchildrenDepth,
|
||||
);
|
||||
},
|
||||
|
||||
async generateGraph() {
|
||||
this.loading = true;
|
||||
// biome-ignore lint/correctness/noUndeclaredVariables: defined by user_godfathers_tree.jinja
|
||||
this.graph = await createGraph($(this.$refs.graph), this.graphData, activeUser);
|
||||
this.loading = false;
|
||||
},
|
||||
}));
|
||||
});
|
||||
@@ -1,7 +0,0 @@
|
||||
/**
|
||||
* Minified by jsDelivr using Terser v5.15.1.
|
||||
* Original file: /npm/cytoscape-cxtmenu@3.5.0/cytoscape-cxtmenu.js
|
||||
*
|
||||
* Do NOT use SRI with dynamically generated files! More information: https://www.jsdelivr.com/using-sri-with-dynamic-files
|
||||
*/
|
||||
!function(t,e){"object"==typeof exports&&"object"==typeof module?module.exports=e():"function"==typeof define&&define.amd?define([],e):"object"==typeof exports?exports.cytoscapeCxtmenu=e():t.cytoscapeCxtmenu=e()}(this,(function(){return function(t){var e={};function i(n){if(e[n])return e[n].exports;var o=e[n]={i:n,l:!1,exports:{}};return t[n].call(o.exports,o,o.exports,i),o.l=!0,o.exports}return i.m=t,i.c=e,i.i=function(t){return t},i.d=function(t,e,n){i.o(t,e)||Object.defineProperty(t,e,{configurable:!1,enumerable:!0,get:n})},i.n=function(t){var e=t&&t.__esModule?function(){return t.default}:function(){return t};return i.d(e,"a",e),e},i.o=function(t,e){return Object.prototype.hasOwnProperty.call(t,e)},i.p="",i(i.s=4)}([function(t,e,i){"use strict";var n=i(2),o=i(1),a=i(3),d=a.removeEles,r=a.setStyles,l=a.createElement,s=a.getPixelRatio,c=a.getOffset;t.exports=function(t){var e=o({},n,t),i=this,a=i.container(),u=void 0,p={options:e,handlers:[],container:l({class:"cxtmenu"})},h=p.container,g=l(),f=l({tag:"canvas"}),m=[],v=f.getContext("2d"),x=100,P=2*(x+e.activePadding),b=void 0,y=void 0;function S(t,e){E.drawBg=[t,e]}function M(t,i){v.globalCompositeOperation="source-over",v.clearRect(0,0,P,P),v.fillStyle=e.fillColor;for(var n=2*Math.PI/m.length,o=Math.PI/2,a=o+n,d=0;d<m.length;d++){var r=m[d];r.fillColor&&(v.fillStyle=r.fillColor),v.beginPath(),v.moveTo(t+e.activePadding,t+e.activePadding),v.arc(t+e.activePadding,t+e.activePadding,t,2*Math.PI-o,2*Math.PI-a,!0),v.closePath(),v.fill(),o+=n,a+=n,v.fillStyle=e.fillColor}v.globalCompositeOperation="destination-out",v.strokeStyle="white",v.lineWidth=e.separatorWidth,a=(o=Math.PI/2)+n;for(var l=0;l<m.length;l++){var s=t*Math.cos(o),c=t*Math.sin(o);v.beginPath(),v.moveTo(t+e.activePadding,t+e.activePadding),v.lineTo(t+e.activePadding+s,t+e.activePadding-c),v.closePath(),v.stroke(),o+=n,a+=n}v.fillStyle="white",v.globalCompositeOperation="destination-out",v.beginPath(),v.arc(t+e.activePadding,t+e.activePadding,i+e.spotlightPadding,0,2*Math.PI,!0),v.closePath(),v.fill(),v.globalCompositeOperation="source-over"}function w(t,i,n,o,a){var d=2*Math.PI/m.length,r=Math.PI/2,l=r+d;r+=d*b,l+=d*b,v.fillStyle=e.activeFillColor,v.strokeStyle="black",v.lineWidth=1,v.beginPath(),v.moveTo(n+e.activePadding,n+e.activePadding),v.arc(n+e.activePadding,n+e.activePadding,n+e.activePadding,2*Math.PI-r,2*Math.PI-l,!0),v.closePath(),v.fill(),v.fillStyle="white",v.globalCompositeOperation="destination-out";var s=n+e.activePadding+t/n*(a+e.spotlightPadding-e.indicatorSize/4),c=n+e.activePadding+i/n*(a+e.spotlightPadding-e.indicatorSize/4),u=Math.PI/4-o;v.translate(s,c),v.rotate(u);var p=e.indicatorSize>a+e.spotlightPadding?a+e.spotlightPadding:e.indicatorSize;v.beginPath(),v.fillRect(-p/2,-p/2,p,p),v.closePath(),v.fill(),v.rotate(-u),v.translate(-s,-c),v.beginPath(),v.arc(n+e.activePadding,n+e.activePadding,a+e.spotlightPadding,0,2*Math.PI,!0),v.closePath(),v.fill(),v.globalCompositeOperation="source-over"}function C(){var t=s(),e=P,i=P;f.width=e*t,f.height=i*t,f.style.width=e+"px",f.style.height=i+"px",v.setTransform(1,0,0,1,0,0),v.scale(t,t)}a.insertBefore(h,a.firstChild),h.appendChild(g),g.appendChild(f),r(h,{position:"absolute",zIndex:e.zIndex,userSelect:"none",pointerEvents:"none"}),["mousedown","mousemove","mouseup","contextmenu"].forEach((function(t){h.addEventListener(t,(function(t){return t.preventDefault(),!1}))})),r(g,{display:"none",width:P+"px",height:P+"px",position:"absolute",zIndex:1,marginLeft:-e.activePadding+"px",marginTop:-e.activePadding+"px",userSelect:"none"}),f.width=P,f.height=P;var R=!0,E={},I=window.requestAnimationFrame||window.webkitRequestAnimationFrame||window.mozRequestAnimationFrame||window.msRequestAnimationFrame||function(t){return setTimeout(t,16)};C(),function t(){E.drawBg&&M.apply(null,E.drawBg),E.drawCommands&&w.apply(null,E.drawCommands),E={},R&&I(t)}();var O,T,F,z,N,j,k,L,A,q=void 0,W=void 0,B=void 0,H={on:function(t,e,n){var o=n;return"core"===e&&(o=function(t){if(t.cyTarget===i||t.target===i)return n.apply(this,[t])}),p.handlers.push({events:t,selector:e,fn:o}),"core"===e?i.on(t,o):i.on(t,e,o),this}};function X(){R=!1,function(){for(var t=p.handlers,e=0;e<t.length;e++){var n=t[e];"core"===n.selector?i.off(n.events,n.fn):i.off(n.events,n.selector,n.fn)}window.removeEventListener("resize",C)}(),h.remove()}return T=void 0,F=!1,z=void 0,N=void 0,j=void 0,k=void 0,L=void 0,A=function(){T&&u.grabify(),z&&i.userZoomingEnabled(!0),N&&i.userPanningEnabled(!0),j&&i.boxSelectionEnabled(!0)},window.addEventListener("resize",C),H.on("resize",(function(){C()})).on(e.openMenuEvents,e.selector,(function(t){u=this;var n=this,o=this===i;if(F&&(g.style.display="none",F=!1,A()),"function"==typeof e.commands){var s=e.commands(u);s.then?s.then((function(t){m=t,p()})):(m=s,p())}else m=e.commands,p();function p(){if(m&&0!==m.length){z=i.userZoomingEnabled(),i.userZoomingEnabled(!1),N=i.userPanningEnabled(),i.userPanningEnabled(!1),j=i.boxSelectionEnabled(),i.boxSelectioLine truncated
|
||||
@@ -1,7 +0,0 @@
|
||||
/**
|
||||
* Minified by jsDelivr using Terser v5.3.0.
|
||||
* Original file: /npm/cytoscape-klay@3.1.4/cytoscape-klay.js
|
||||
*
|
||||
* Do NOT use SRI with dynamically generated files! More information: https://www.jsdelivr.com/using-sri-with-dynamic-files
|
||||
*/
|
||||
!function(e,r){"object"==typeof exports&&"object"==typeof module?module.exports=r(require("klayjs")):"function"==typeof define&&define.amd?define(["klayjs"],r):"object"==typeof exports?exports.cytoscapeKlay=r(require("klayjs")):e.cytoscapeKlay=r(e.$klay)}(this,(function(e){return function(e){var r={};function n(t){if(r[t])return r[t].exports;var i=r[t]={i:t,l:!1,exports:{}};return e[t].call(i.exports,i,i.exports,n),i.l=!0,i.exports}return n.m=e,n.c=r,n.i=function(e){return e},n.d=function(e,r,t){n.o(e,r)||Object.defineProperty(e,r,{configurable:!1,enumerable:!0,get:t})},n.n=function(e){var r=e&&e.__esModule?function(){return e.default}:function(){return e};return n.d(r,"a",r),r},n.o=function(e,r){return Object.prototype.hasOwnProperty.call(e,r)},n.p="",n(n.s=3)}([function(e,r,n){"use strict";var t=n(4),i=n(1),a=n(2),o={addUnnecessaryBendpoints:"de.cau.cs.kieler.klay.layered.unnecessaryBendpoints",alignment:"de.cau.cs.kieler.alignment",aspectRatio:"de.cau.cs.kieler.aspectRatio",borderSpacing:"borderSpacing",compactComponents:"de.cau.cs.kieler.klay.layered.components.compact",compactionStrategy:"de.cau.cs.kieler.klay.layered.nodeplace.compactionStrategy",contentAlignment:"de.cau.cs.kieler.klay.layered.contentAlignment",crossingMinimization:"de.cau.cs.kieler.klay.layered.crossMin",cycleBreaking:"de.cau.cs.kieler.klay.layered.cycleBreaking",debugMode:"de.cau.cs.kieler.debugMode",direction:"de.cau.cs.kieler.direction",edgeLabelSideSelection:"de.cau.cs.kieler.klay.layered.edgeLabelSideSelection",edgeRouting:"de.cau.cs.kieler.edgeRouting",edgeSpacingFactor:"de.cau.cs.kieler.klay.layered.edgeSpacingFactor",feedbackEdges:"de.cau.cs.kieler.klay.layered.feedBackEdges",fixedAlignment:"de.cau.cs.kieler.klay.layered.fixedAlignment",greedySwitchCrossingMinimization:"de.cau.cs.kieler.klay.layered.greedySwitch",hierarchyHandling:"de.cau.cs.kieler.hierarchyHandling",inLayerSpacingFactor:"de.cau.cs.kieler.klay.layered.inLayerSpacingFactor",interactiveReferencePoint:"de.cau.cs.kieler.klay.layered.interactiveReferencePoint",layerConstraint:"de.cau.cs.kieler.klay.layered.layerConstraint",layoutHierarchy:"de.cau.cs.kieler.layoutHierarchy",linearSegmentsDeflectionDampening:"de.cau.cs.kieler.klay.layered.linearSegmentsDeflectionDampening",mergeEdges:"de.cau.cs.kieler.klay.layered.mergeEdges",mergeHierarchyCrossingEdges:"de.cau.cs.kieler.klay.layered.mergeHierarchyEdges",noLayout:"de.cau.cs.kieler.noLayout",nodeLabelPlacement:"de.cau.cs.kieler.nodeLabelPlacement",nodeLayering:"de.cau.cs.kieler.klay.layered.nodeLayering",nodePlacement:"de.cau.cs.kieler.klay.layered.nodePlace",portAlignment:"de.cau.cs.kieler.portAlignment",portAlignmentEastern:"de.cau.cs.kieler.portAlignment.east",portAlignmentNorth:"de.cau.cs.kieler.portAlignment.north",portAlignmentSouth:"de.cau.cs.kieler.portAlignment.south",portAlignmentWest:"de.cau.cs.kieler.portAlignment.west",portConstraints:"de.cau.cs.kieler.portConstraints",portLabelPlacement:"de.cau.cs.kieler.portLabelPlacement",portOffset:"de.cau.cs.kieler.offset",portSide:"de.cau.cs.kieler.portSide",portSpacing:"de.cau.cs.kieler.portSpacing",postCompaction:"de.cau.cs.kieler.klay.layered.postCompaction",priority:"de.cau.cs.kieler.priority",randomizationSeed:"de.cau.cs.kieler.randomSeed",routeSelfLoopInside:"de.cau.cs.kieler.selfLoopInside",separateConnectedComponents:"de.cau.cs.kieler.separateConnComp",sizeConstraint:"de.cau.cs.kieler.sizeConstraint",sizeOptions:"de.cau.cs.kieler.sizeOptions",spacing:"de.cau.cs.kieler.spacing",splineSelfLoopPlacement:"de.cau.cs.kieler.klay.layered.splines.selfLoopPlacement",thoroughness:"de.cau.cs.kieler.klay.layered.thoroughness",wideNodesOnMultipleLayers:"de.cau.cs.kieler.klay.layered.wideNodesOnMultipleLayers"},c=function(e){for(var r=Object.keys(e),n={},t=0;t<r.length;t++){var i=r[t],a=o[i],c=e[i];n[a]=c}return n},s={interactiveReferencePoint:"CENTER"},l=function(e){for(var r=e.parent(),n=e.scratch("klay"),t={x:n.x,y:n.y};r.nonempty();){var i=r.scratch("klay");t.x+=i.x,t.y+=i.y,r=r.parent()}return t},d=function(e,r){var n=e.layoutDimensions(r),t=e.numericStyle("padding"),i={_cyEle:e,id:e.id(),padding:{top:t,left:t,bottom:t,right:t}};return e.isParent()||(i.width=n.w,i.height=n.h),e.scratch("klay",i),i},u=function(e,r){var n={_cyEle:e,id:e.id(),source:e.data("source"),target:e.data("target"),properties:{}},t=r.priority(e);return null!=t&&(n.properties.priority=t),e.scratch("klay",n),n};function p(e){var r=e.klay;this.options=i({},a,e),this.options.klay=i({},a.klay,r,s)}p.prototype.run=function(){var e=this.options,r=e.eles,n=r.nodes(),i=function(e,r,n){for(var t=[],i=[],a={},o={id:"root",children:[],edges:[]},c=0;c<e.length;c++){var s=e[c],l=d(s,n);t.push(l),a[s.id()]=l}for(var p=0;p<r.length;p++){var y=r[p],g=u(y,n);i.push(g),a[y.id()]=g}for(var k=0;k<t.length;k++){var f=t[k],m=f._cyEle;if(m.isChild()){var h=a[m.parent().id()];(h.children=h.children||[]).push(f)}else o.children.push(f)}for(var S=0;S<i.length;S++){var E=i[S],v=E._cyEle;v.source().parent(),v.target().parLine truncated
|
||||
-32
@@ -1,32 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2016-2024, The Cytoscape Consortium.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
* this software and associated documentation files (the “Software”), to deal in
|
||||
* the Software without restriction, including without limitation the rights to
|
||||
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
* of the Software, and to permit persons to whom the Software is furnished to do
|
||||
* so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?module.exports=t():"function"==typeof define&&define.amd?define(t):(e="undefined"!=typeof globalThis?globalThis:e||self).cytoscape=t()}(this,(function(){"use strict";function e(t){return(e="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e})(t)}function t(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}function n(e,t){for(var n=0;n<t.length;n++){var r=t[n];r.enumerable=r.enumerable||!1,r.configurable=!0,"value"in r&&(r.writable=!0),Object.defineProperty(e,r.key,r)}}function r(e,t,r){return t&&n(e.prototype,t),r&&n(e,r),Object.defineProperty(e,"prototype",{writable:!1}),e}function i(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function a(e,t){return function(e){if(Array.isArray(e))return e}(e)||function(e,t){var n=null==e?null:"undefined"!=typeof Symbol&&e[Symbol.iterator]||e["@@iterator"];if(null==n)return;var r,i,a=[],o=!0,s=!1;try{for(n=n.call(e);!(o=(r=n.next()).done)&&(a.push(r.value),!t||a.length!==t);o=!0);}catch(e){s=!0,i=e}finally{try{o||null==n.return||n.return()}finally{if(s)throw i}}return a}(e,t)||o(e,t)||function(){throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}()}function o(e,t){if(e){if("string"==typeof e)return s(e,t);var n=Object.prototype.toString.call(e).slice(8,-1);return"Object"===n&&e.constructor&&(n=e.constructor.name),"Map"===n||"Set"===n?Array.from(e):"Arguments"===n||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)?s(e,t):void 0}}function s(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=new Array(t);n<t;n++)r[n]=e[n];return r}function l(e,t){var n="undefined"!=typeof Symbol&&e[Symbol.iterator]||e["@@iterator"];if(!n){if(Array.isArray(e)||(n=o(e))||t&&e&&"number"==typeof e.length){n&&(e=n);var r=0,i=function(){};return{s:i,n:function(){return r>=e.length?{done:!0}:{done:!1,value:e[r++]}},e:function(e){throw e},f:i}}throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}var a,s=!0,l=!1;return{s:function(){n=n.call(e)},n:function(){var e=n.next();return s=e.done,e},e:function(e){l=!0,a=e},f:function(){try{s||null==n.return||n.return()}finally{if(l)throw a}}}}var u="undefined"==typeof window?null:window,c=u?u.navigator:null;u&&u.document;var d=e(""),h=e({}),p=e((function(){})),f="undefined"==typeof HTMLElement?"undefined":e(HTMLElement),g=function(e){return e&&e.instanceString&&y(e.instanceString)?e.instanceString():null},v=function(t){return null!=t&&e(t)==d},y=function(t){return null!=t&&e(t)===p},m=function(e){return!E(e)&&(Array.isArray?Array.isArray(e):null!=e&&e instanceof Array)},b=function(t){return null!=t&&e(t)===h&&!m(t)&&t.constructor===Object},x=function(t){return null!=t&&e(t)===e(1)&&!isNaN(t)},w=function(e){return"undefined"===f?void 0:null!=e&&e instanceof HTMLElement},E=function(e){return k(e)||C(e)},k=function(e){return"collection"===g(e)&&e._private.single},C=function(e){return"collection"===g(e)&&!e._private.single},S=function(e){return"core"===g(e)},P=function(e){return"stylesheet"===g(e)},D=function(e){return null==e||!(""!==e&&!e.match(/^\s+$/))},T=function(t){return function(t){return null!=t&&e(t)===h}(t)&&y(t.then)},_=function(e,t){t||(t=function(){if(1===arguments.length)return arguments[0];if(0===arguments.length)return"undefined";for(var e=[],t=0;t<arguments.length;t++)e.push(arguments[t]);return e.join("$")});var n=function n(){var r,i=this,a=arguments,o=t.apply(i,a),s=n.cache;return(r=s[o])||(r=s[o]=e.apply(i,a)),r};return n.cache={},n},M=_((function(e){return e.replace(/([A-Z])/g,(function(e){return"-"+e.toLowerCase()}))})),B=_((function(e){return e.replace(/(-\w)/g,(function(e){return e[1].toUpperCase()}))})),N=_((function(e,t){return e+t[0].toUpperCase()+t.substring(1)}),(function(e,t){return e+"$"+t})),z=function(e){return D(e)?e:e.charAt(0).toUpperCase()+e.substring(1)},I="(?:[-+]?(?:(?:\\d+|\\d*\\.\\d+)(?:[Ee][+-]?\\d+)?))",A=function(e,t){return e<t?-1:e>t?1:0},L=null!=Object.assign?Object.assign.bind(Object):function(e){for(var t=arguments,n=1;n<t.length;n++){var r=t[n];if(null!=r)for(var i=Object.keys(r),a=0;a<i.length;a++){var o=i[a];e[o]=r[o]}}return e},O=function(e){return(m(e)?e:null)||function(e){return R[e.toLowerCase()]}(e)||function(e){if((4===e.length||7===e.length)&&"#"===e[0]){var t,n,r;return 4===e.length?(t=parseInt(e[1]+e[1],16),n=parseInt(e[2]+e[2],16),r=parseInt(e[3]+e[3],16)):(t=parseInt(e[1]+e[2],16),n=parseInt(e[3]+e[4],16),r=parseInt(e[5]+e[6],16)),[t,n,r]}}(e)||function(e){var t,n=new RegExp("^rgb[a]?\\(((?:[-+]?(?:(?:\\d+|\\d*\\.\\d+)(?:[Ee][+-]?\\d+)?))[%]?)\\s*,\\s*((?:[-+]?(?:(?:\\d+|\\dLine truncated
|
||||
/*!
|
||||
Embeddable Minimum Strictly-Compliant Promises/A+ 1.1.1 Thenable
|
||||
Copyright (c) 2013-2014 Ralf S. Engelschall (http://engelschall.com)
|
||||
Licensed under The MIT License (http://opensource.org/licenses/MIT)
|
||||
*/
|
||||
var cr=function e(t){if(!(this instanceof e))return new e(t);this.id="Thenable/1.0.7",this.state=0,this.fulfillValue=void 0,this.rejectReason=void 0,this.onFulfilled=[],this.onRejected=[],this.proxy={then:this.then.bind(this)},"function"==typeof t&&t.call(this,this.fulfill.bind(this),this.reject.bind(this))};cr.prototype={fulfill:function(e){return dr(this,1,"fulfillValue",e)},reject:function(e){return dr(this,2,"rejectReason",e)},then:function(e,t){var n=new cr;return this.onFulfilled.push(fr(e,n,"fulfill")),this.onRejected.push(fr(t,n,"reject")),hr(this),n.proxy}};var dr=function(e,t,n,r){return 0===e.state&&(e.state=t,e[n]=r,hr(e)),e},hr=function(e){1===e.state?pr(e,"onFulfilled",e.fulfillValue):2===e.state&&pr(e,"onRejected",e.rejectReason)},pr=function(e,t,n){if(0!==e[t].length){var r=e[t];e[t]=[];var i=function(){for(var e=0;e<r.length;e++)r[e](n)};"function"==typeof setImmediate?setImmediate(i):setTimeout(i,0)}},fr=function(e,t,n){return function(r){if("function"!=typeof e)t[n].call(t,r);else{var i;try{i=e(r)}catch(e){return void t.reject(e)}gr(t,i)}}},gr=function t(n,r){if(n!==r&&n.proxy!==r){var i;if("object"===e(r)&&null!==r||"function"==typeof r)try{i=r.then}catch(e){return void n.reject(e)}if("function"!=typeof i)n.fulfill(r);else{var a=!1;try{i.call(r,(function(e){a||(a=!0,e===r?n.reject(new TypeError("circular thenable chain")):t(n,e))}),(function(e){a||(a=!0,n.reject(e))}))}catch(e){a||n.reject(e)}}}else n.reject(new TypeError("cannot resolve promise with itself"))};cr.all=function(e){return new cr((function(t,n){for(var r=new Array(e.length),i=0,a=function(n,a){r[n]=a,++i===e.length&&t(r)},o=0;o<e.length;o++)!function(t){var r=e[t];null!=r&&null!=r.then?r.then((function(e){a(t,e)}),(function(e){n(e)})):a(t,r)}(o)}))},cr.resolve=function(e){return new cr((function(t,n){t(e)}))},cr.reject=function(e){return new cr((function(t,n){n(e)}))};var vr="undefined"!=typeof Promise?Promise:cr,yr=function(e,t,n){var r=S(e),i=!r,a=this._private=L({duration:1e3},t,n);if(a.target=e,a.style=a.style||a.css,a.started=!1,a.playing=!1,a.hooked=!1,a.applying=!1,a.progress=0,a.completes=[],a.frames=[],a.complete&&y(a.complete)&&a.completes.push(a.complete),i){var o=e.position();a.startPosition=a.startPosition||{x:o.x,y:o.y},a.startStyle=a.startStyle||e.cy().style().getAnimationStartStyle(e,a.style)}if(r){var s=e.pan();a.startPan={x:s.x,y:s.y},a.startZoom=e.zoom()}this.length=1,this[0]=this},mr=yr.prototype;L(mr,{instanceString:function(){return"animation"},hook:function(){var e=this._private;if(!e.hooked){var t=e.target._private.animation;(e.queue?t.queue:t.current).push(this),E(e.target)&&e.target.cy().addToAnimationPool(e.target),e.hooked=!0}return this},play:function(){var e=this._private;return 1===e.progress&&(e.progress=0),e.playing=!0,e.started=!1,e.stopped=!1,this.hook(),this},playing:function(){return this._private.playing},apply:function(){var e=this._private;return e.applying=!0,e.started=!1,e.stopped=!1,this.hook(),this},applying:function(){return this._private.applying},pause:function(){var e=this._private;return e.playing=!1,e.started=!1,this},stop:function(){var e=this._private;return e.playing=!1,e.started=!1,e.stopped=!0,this},rewind:function(){return this.progress(0)},fastforward:function(){return this.progress(1)},time:function(e){var t=this._private;return void 0===e?t.progress*t.duration:this.progress(e/t.duration)},progress:function(e){var t=this._private,n=t.playing;return void 0===e?t.progress:(n&&this.pause(),t.progress=e,t.started=!1,n&&this.play(),this)},completed:function(){return 1===this._private.progress},reverse:function(){var e=this._private,t=e.playing;t&&this.pause(),e.progress=1-e.progress,e.started=!1;var n=function(t,n){var r=e[t];null!=r&&(e[t]=e[n],e[n]=r)};if(n("zoom","startZoom"),n("pan","startPan"),n("position","startPosition"),e.style)for(var r=0;r<e.style.length;r++){var i=e.style[r],a=i.name,o=e.startStyle[a];e.startStyle[a]=i,e.style[r]=o}return t&&this.play(),this},promise:function(e){var t,n=this._private;switch(e){case"frame":t=n.frames;break;default:case"complete":case"completed":t=n.completes}return new vr((function(e,n){t.push((function(){e()}))}))}}),mr.complete=mr.completed,mr.run=mr.play,mr.running=mr.playing;var br={animated:function(){return function(){var e=void 0!==this.length?this:[this];if(!(this._private.cy||this).styleEnabled())return!1;var t=e[0];return t?t._private.animation.current.length>0:void 0}},clearQueue:function(){return function(){var e=void 0!==this.length?this:[this];if(!(this._private.cy||this).styleEnabled())return this;for(var t=0;t<e.length;t++){e[t]._private.animation.queue=[]}return this}},delay:function(){return function(e,t){return(this._private.cy||this).styleEnabled()?this.animate({delay:e,duration:e,complete:t}):this}},delayAnimation:function(){return function(e,t){return(this._private.cy||this).styleEnabled()?this.animation({delay:e,duration:e,complete:t}):this}},animation:function(){return function(e,t){var n=void 0!==this.lLine truncated
|
||||
/*! Bezier curve function generator. Copyright Gaetan Renaudeau. MIT License: http://en.wikipedia.org/wiki/MIT_License */
|
||||
/*! Runge-Kutta spring physics function generator. Adapted from Framer.js, copyright Koen Bok. MIT License: http://en.wikipedia.org/wiki/MIT_License */
|
||||
var is=function(){function e(e){return-e.tension*e.x-e.friction*e.v}function t(t,n,r){var i={x:t.x+r.dx*n,v:t.v+r.dv*n,tension:t.tension,friction:t.friction};return{dx:i.v,dv:e(i)}}function n(n,r){var i={dx:n.v,dv:e(n)},a=t(n,.5*r,i),o=t(n,.5*r,a),s=t(n,r,o),l=1/6*(i.dx+2*(a.dx+o.dx)+s.dx),u=1/6*(i.dv+2*(a.dv+o.dv)+s.dv);return n.x=n.x+l*r,n.v=n.v+u*r,n}return function e(t,r,i){var a,o,s,l={x:-1,v:0,tension:null,friction:null},u=[0],c=0;for(t=parseFloat(t)||500,r=parseFloat(r)||20,i=i||null,l.tension=t,l.friction=r,o=(a=null!==i)?(c=e(t,r))/i*.016:.016;s=n(s||l,o),u.push(1+s.x),c+=16,Math.abs(s.x)>1e-4&&Math.abs(s.v)>1e-4;);return a?function(e){return u[e*(u.length-1)|0]}:c}}(),as=function(e,t,n,r){var i=function(e,t,n,r){var i=4,a=.001,o=1e-7,s=10,l=11,u=1/(l-1),c="undefined"!=typeof Float32Array;if(4!==arguments.length)return!1;for(var d=0;d<4;++d)if("number"!=typeof arguments[d]||isNaN(arguments[d])||!isFinite(arguments[d]))return!1;e=Math.min(e,1),n=Math.min(n,1),e=Math.max(e,0),n=Math.max(n,0);var h=c?new Float32Array(l):new Array(l);function p(e,t){return 1-3*t+3*e}function f(e,t){return 3*t-6*e}function g(e){return 3*e}function v(e,t,n){return((p(t,n)*e+f(t,n))*e+g(t))*e}function y(e,t,n){return 3*p(t,n)*e*e+2*f(t,n)*e+g(t)}function m(t,r){for(var a=0;a<i;++a){var o=y(r,e,n);if(0===o)return r;r-=(v(r,e,n)-t)/o}return r}function b(){for(var t=0;t<l;++t)h[t]=v(t*u,e,n)}function x(t,r,i){var a,l,u=0;do{(a=v(l=r+(i-r)/2,e,n)-t)>0?i=l:r=l}while(Math.abs(a)>o&&++u<s);return l}function w(t){for(var r=0,i=1,o=l-1;i!==o&&h[i]<=t;++i)r+=u;--i;var s=r+(t-h[i])/(h[i+1]-h[i])*u,c=y(s,e,n);return c>=a?m(t,s):0===c?s:x(t,r,r+u)}var E=!1;function k(){E=!0,e===t&&n===r||b()}var C=function(i){return E||k(),e===t&&n===r?i:0===i?0:1===i?1:v(w(i),t,r)};C.getControlPoints=function(){return[{x:e,y:t},{x:n,y:r}]};var S="generateBezier("+[e,t,n,r]+")";return C.toString=function(){return S},C}(e,t,n,r);return function(e,t,n){return e+(t-e)*i(n)}},os={linear:function(e,t,n){return e+(t-e)*n},ease:as(.25,.1,.25,1),"ease-in":as(.42,0,1,1),"ease-out":as(0,0,.58,1),"ease-in-out":as(.42,0,.58,1),"ease-in-sine":as(.47,0,.745,.715),"ease-out-sine":as(.39,.575,.565,1),"ease-in-out-sine":as(.445,.05,.55,.95),"ease-in-quad":as(.55,.085,.68,.53),"ease-out-quad":as(.25,.46,.45,.94),"ease-in-out-quad":as(.455,.03,.515,.955),"ease-in-cubic":as(.55,.055,.675,.19),"ease-out-cubic":as(.215,.61,.355,1),"ease-in-out-cubic":as(.645,.045,.355,1),"ease-in-quart":as(.895,.03,.685,.22),"ease-out-quart":as(.165,.84,.44,1),"ease-in-out-quart":as(.77,0,.175,1),"ease-in-quint":as(.755,.05,.855,.06),"ease-out-quint":as(.23,1,.32,1),"ease-in-out-quint":as(.86,0,.07,1),"ease-in-expo":as(.95,.05,.795,.035),"ease-out-expo":as(.19,1,.22,1),"ease-in-out-expo":as(1,0,0,1),"ease-in-circ":as(.6,.04,.98,.335),"ease-out-circ":as(.075,.82,.165,1),"ease-in-out-circ":as(.785,.135,.15,.86),spring:function(e,t,n){if(0===n)return os.linear;var r=is(e,t,n);return function(e,t,n){return e+(t-e)*r(n)}},"cubic-bezier":as};function ss(e,t,n,r,i){if(1===r)return n;if(t===n)return n;var a=i(t,n,r);return null==e||((e.roundValue||e.color)&&(a=Math.round(a)),void 0!==e.min&&(a=Math.max(a,e.min)),void 0!==e.max&&(a=Math.min(a,e.max))),a}function ls(e,t){return null!=e.pfValue||null!=e.value?null==e.pfValue||null!=t&&"%"===t.type.units?e.value:e.pfValue:e}function us(e,t,n,r,i){var a=null!=i?i.type:null;n<0?n=0:n>1&&(n=1);var o=ls(e,i),s=ls(t,i);if(x(o)&&x(s))return ss(a,o,s,n,r);if(m(o)&&m(s)){for(var l=[],u=0;u<s.length;u++){var c=o[u],d=s[u];if(null!=c&&null!=d){var h=ss(a,c,d,n,r);l.push(h)}else l.push(d)}return l}}function cs(e,t,n,r){var i=!r,a=e._private,o=t._private,s=o.easing,l=o.startTime,u=(r?e:e.cy()).style();if(!o.easingImpl)if(null==s)o.easingImpl=os.linear;else{var c,d,h;if(v(s))c=u.parse("transition-timing-function",s).value;else c=s;v(c)?(d=c,h=[]):(d=c[1],h=c.slice(2).map((function(e){return+e}))),h.length>0?("spring"===d&&h.push(o.duration),o.easingImpl=os[d].apply(null,h)):o.easingImpl=os[d]}var p,f=o.easingImpl;if(p=0===o.duration?1:(n-l)/o.duration,o.applying&&(p=o.progress),p<0?p=0:p>1&&(p=1),null==o.delay){var g=o.startPosition,y=o.position;if(y&&i&&!e.locked()){var m={};ds(g.x,y.x)&&(m.x=us(g.x,y.x,p,f)),ds(g.y,y.y)&&(m.y=us(g.y,y.y,p,f)),e.position(m)}var b=o.startPan,x=o.pan,w=a.pan,E=null!=x&&r;E&&(ds(b.x,x.x)&&(w.x=us(b.x,x.x,p,f)),ds(b.y,x.y)&&(w.y=us(b.y,x.y,p,f)),e.emit("pan"));var k=o.startZoom,C=o.zoom,S=null!=C&&r;S&&(ds(k,C)&&(a.zoom=Tt(a.minZoom,us(k,C,p,f),a.maxZoom)),e.emit("zoom")),(E||S)&&e.emit("viewport");var P=o.style;if(P&&P.length>0&&i){for(var D=0;D<P.length;D++){var T=P[D],_=T.name,M=T,B=o.startStyle[_],N=us(B,M,p,f,u.properties[B.name]);u.overrideBypass(e,_,N)}e.emit("style")}}return o.progress=p,p}function ds(e,t){return null!=e&&null!=t&&(!(!x(e)||!x(t))||!(!e||!t))}function hs(e,t,n,r){var i=t._private;i.started=!0,i.startTime=n-i.progress*i.duration}function ps(e,t){var n=t._private.aniEles,r=[];function i(t,n){var i=t._private,aLine truncated
|
||||
-7
@@ -1,7 +0,0 @@
|
||||
/**
|
||||
* Minified by jsDelivr using Terser v5.19.2.
|
||||
* Original file: /npm/klayjs@0.4.1/klay.js
|
||||
*
|
||||
* Do NOT use SRI with dynamically generated files! More information: https://www.jsdelivr.com/using-sri-with-dynamic-files
|
||||
*/
|
||||
var klayregister,klaycallback;!function(){var n;function t(){}function e(){}function r(){}function c(){}function i(){}function a(){}function u(){}function f(){}function s(){}function b(){}function h(){}function l(){}function w(){}function d(){}function g(){}function v(){}function k(){}function p(){}function m(){}function j(){}function y(){}function S(){}function E(){}function H(){}function C(){}function I(){}function L(){}function G(){}function N(){}function O(){}function T(){}function P(){}function R(){}function Y(){}function A(){}function _(){}function M(){}function D(){}function x(){}function B(){}function $(){}function U(){}function F(){}function V(){}function z(){}function q(){}function Q(){}function K(){}function W(){}function J(){}function Z(){}function X(){}function nn(){}function tn(){}function en(){}function rn(){}function cn(){}function an(){}function un(){}function on(){}function fn(){}function sn(){}function bn(){}function hn(){}function ln(){}function wn(){}function dn(){}function gn(){}function vn(){}function kn(){}function pn(){}function mn(){}function jn(){}function yn(){}function Sn(){}function En(){}function Hn(){}function Cn(){}function In(){}function Ln(){}function Gn(){}function Nn(){}function On(){}function Tn(){}function Pn(){}function Rn(){}function Yn(){}function An(){}function _n(){}function Mn(){}function Dn(){}function xn(){}function Bn(){}function $n(){}function Un(){}function Fn(){}function Vn(){}function zn(){}function qn(){}function Qn(){}function Kn(){}function Wn(){}function Jn(){}function Zn(){}function Xn(){}function nt(){}function tt(){}function et(){}function rt(){}function ct(){}function it(){}function at(){}function ut(){}function ot(){}function ft(){}function st(){}function bt(){}function ht(){}function lt(){}function wt(){}function dt(){}function gt(){}function vt(){}function kt(){Bh()}function pt(){Ay()}function mt(){Kl()}function jt(){Qd()}function yt(){ni()}function St(){ti()}function Et(){sa()}function Ht(){Kd()}function Ct(){_h()}function It(){DE()}function Lt(){Mh()}function Gt(){Dh()}function Nt(){HI()}function Ot(){FH()}function Tt(){fb(this)}function Pt(){}function Rt(){Sf(this)}function Yt(){}function At(n){this.a=n}function _t(n){this.a=n}function Mt(n){this.a=n}function Dt(n){this.a=n}function xt(n){this.a=n}function Bt(n){this.a=n}function $t(n){this.a=n}function Ut(n){this.a=n}function Ft(n){this.a=n}function Vt(n){this.b=n}function zt(n){this.a=n}function qt(n){this.a=n}function Qt(n){this.a=n}function Kt(n){this.a=n}function Wt(n){this.a=n}function Jt(n){this.a=n}function Zt(n){this.a=n}function Xt(n){this.a=n}function ne(n){this.a=n}function te(n){this.a=n}function ee(n){this.a=n}function re(n){this.a=n}function ce(n){this.a=n}function ie(n){this.a=n}function ae(n){this.a=n}function ue(n){this.e=n}function oe(n){this.a=n}function fe(n){this.a=n}function se(n){this.a=n}function be(n){this.a=n}function he(n){this.a=n}function le(n){this.a=n}function we(n){this.a=n}function de(n){this.a=n}function ge(n){this.a=n}function ve(n){this.a=n}function ke(n){this.a=n}function pe(n){this.a=n}function me(n){this.a=n}function je(n){this.a=n}function ye(n){this.a=n}function Se(n){this.a=n}function Ee(n){this.a=n}function He(n){this.a=n}function Ce(n){this.a=n}function Ie(n){this.a=n}function Le(n){this.a=n}function Ge(n){this.c=n}function Ne(n){this.a=n}function Oe(n){this.a=n}function Te(n){this.a=n}function Pe(n){this.a=n}function Re(n){this.a=n}function Ye(n){this.a=n}function Ae(n){this.a=n}function _e(n){this.a=n}function Me(n){this.a=n}function De(n){this.a=n}function xe(n){this.d=n}function Be(n){this.a=n}function $e(n){this.a=n}function Ue(n){this.a=n}function Fe(n){this.a=n}function Ve(n){this.b=n}function ze(n){this.a=n}function qe(n){this.a=n}function Qe(n){this.c=n}function Ke(n){this.a=n}function We(n){this.a=n}function Je(n){this.a=n}function Ze(n){this.b=n}function Xe(n){this.b=n}function nr(n){this.c=n}function tr(n){this.a=n}function er(n){this.a=n}function rr(n){this.a=n}function cr(){this.a=[]}function ir(n){this.a=n}function ar(n){this.a=n}function ur(n){n.b=n.a}function or(n){n.c=n.d.d}function fr(n,t){n.g=t}function sr(n,t){n.k=t}function br(n,t){n.e.k=t}function hr(n){return n.a}function lr(n){return n.a}function wr(n){return n.a}function dr(n){return n.a}function gr(n){return n.a}function vr(){return null}function kr(){return null}function pr(){this.c=this}function mr(){fb(this)}function jr(){Ik(this)}function yr(n){!function(n,t){var e,r,c,i,a,u,o;for(o=0,r=0,c=t.length;r<c;++r)for(i=0,a=(e=t[r]).length;i<a;++i)for(u=new Qe(e[i].f);u.a<u.c.c.length;)zh(rv(u),7).k=o++;n.a=Pk(OQ,BP,26,o,12,1)}(this,n)}function Sr(n){gf(),function(n){var t,e,r,c,i,a,u,o,f,s;for(c=zh(ca(n,(HT(),J_)),15).a,u=new Qe(AC(n));u.a<u.c.c.length;){for((e=new xN(a=zh(rv(u),626))).d=c,e.k=zh(NS(a,vM),15).a,r=zh(NS(a,dM),149),t=ei(ri(Ob(Pj(zh(a.e,9),(jT(),fz))))),s=new Qe(HH(a));s.a<s.c.c.length;)f=zh(rv(s),161),r==(Vp(),XM)?fO(f,t,c):r==nD&&AO(f,c),qG(f);zO(e,zh(NS(a,Line truncated
|
||||
@@ -0,0 +1,259 @@
|
||||
import cytoscape from "cytoscape";
|
||||
import cxtmenu from "cytoscape-cxtmenu";
|
||||
import klay from "cytoscape-klay";
|
||||
|
||||
cytoscape.use(klay);
|
||||
cytoscape.use(cxtmenu);
|
||||
|
||||
async function getGraphData(url, godfathersDepth, godchildrenDepth) {
|
||||
const data = await (
|
||||
await fetch(
|
||||
`${url}?godfathers_depth=${godfathersDepth}&godchildren_depth=${godchildrenDepth}`,
|
||||
)
|
||||
).json();
|
||||
return [
|
||||
...data.users.map((user) => {
|
||||
return { data: user };
|
||||
}),
|
||||
...data.relationships.map((rel) => {
|
||||
return {
|
||||
data: { source: rel.godfather, target: rel.godchild },
|
||||
};
|
||||
}),
|
||||
];
|
||||
}
|
||||
|
||||
function createGraph(container, data, activeUserId) {
|
||||
const cy = cytoscape({
|
||||
boxSelectionEnabled: false,
|
||||
autounselectify: true,
|
||||
|
||||
container,
|
||||
elements: data,
|
||||
minZoom: 0.5,
|
||||
|
||||
style: [
|
||||
// the stylesheet for the graph
|
||||
{
|
||||
selector: "node",
|
||||
style: {
|
||||
label: "data(display_name)",
|
||||
"background-image": "data(profile_pict)",
|
||||
width: "100%",
|
||||
height: "100%",
|
||||
"background-fit": "cover",
|
||||
"background-repeat": "no-repeat",
|
||||
shape: "ellipse",
|
||||
},
|
||||
},
|
||||
|
||||
{
|
||||
selector: "edge",
|
||||
style: {
|
||||
width: 5,
|
||||
"line-color": "#ccc",
|
||||
"target-arrow-color": "#ccc",
|
||||
"target-arrow-shape": "triangle",
|
||||
"curve-style": "bezier",
|
||||
},
|
||||
},
|
||||
|
||||
{
|
||||
selector: ".traversed",
|
||||
style: {
|
||||
"border-width": "5px",
|
||||
"border-style": "solid",
|
||||
"border-color": "red",
|
||||
"target-arrow-color": "red",
|
||||
"line-color": "red",
|
||||
},
|
||||
},
|
||||
|
||||
{
|
||||
selector: ".not-traversed",
|
||||
style: {
|
||||
"line-opacity": "0.5",
|
||||
"background-opacity": "0.5",
|
||||
"background-image-opacity": "0.5",
|
||||
},
|
||||
},
|
||||
],
|
||||
layout: {
|
||||
name: "klay",
|
||||
nodeDimensionsIncludeLabels: true,
|
||||
fit: true,
|
||||
klay: {
|
||||
addUnnecessaryBendpoints: true,
|
||||
direction: "DOWN",
|
||||
nodePlacement: "INTERACTIVE",
|
||||
layoutHierarchy: true,
|
||||
},
|
||||
},
|
||||
});
|
||||
const activeUser = cy.getElementById(activeUserId).style("shape", "rectangle");
|
||||
/* Reset graph */
|
||||
const resetGraph = () => {
|
||||
cy.elements((element) => {
|
||||
if (element.hasClass("traversed")) {
|
||||
element.removeClass("traversed");
|
||||
}
|
||||
if (element.hasClass("not-traversed")) {
|
||||
element.removeClass("not-traversed");
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
const onNodeTap = (el) => {
|
||||
resetGraph();
|
||||
/* Create path on graph if selected isn't the targeted user */
|
||||
if (el === activeUser) {
|
||||
return;
|
||||
}
|
||||
cy.elements((element) => {
|
||||
element.addClass("not-traversed");
|
||||
});
|
||||
|
||||
for (const traversed of cy.elements().aStar({
|
||||
root: el,
|
||||
goal: activeUser,
|
||||
}).path) {
|
||||
traversed.removeClass("not-traversed");
|
||||
traversed.addClass("traversed");
|
||||
}
|
||||
};
|
||||
|
||||
cy.on("tap", "node", (tapped) => {
|
||||
onNodeTap(tapped.target);
|
||||
});
|
||||
cy.zoomingEnabled(false);
|
||||
|
||||
/* Add context menu */
|
||||
cy.cxtmenu({
|
||||
selector: "node",
|
||||
|
||||
commands: [
|
||||
{
|
||||
content: '<i class="fa fa-external-link fa-2x"></i>',
|
||||
select: (el) => {
|
||||
window.open(el.data().profile_url, "_blank").focus();
|
||||
},
|
||||
},
|
||||
|
||||
{
|
||||
content: '<span class="fa fa-mouse-pointer fa-2x"></span>',
|
||||
select: (el) => {
|
||||
onNodeTap(el);
|
||||
},
|
||||
},
|
||||
|
||||
{
|
||||
content: '<i class="fa fa-eraser fa-2x"></i>',
|
||||
select: (_) => {
|
||||
resetGraph();
|
||||
},
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
return cy;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a family graph of an user
|
||||
* @param {string} Base url for fetching the tree as a string
|
||||
* @param {string} Id of the user to fetch the tree from
|
||||
* @param {number} Minimum tree depth for godfathers and godchildren
|
||||
* @param {number} Maximum tree depth for godfathers and godchildren
|
||||
**/
|
||||
window.loadFamilyGraph = (apiUrl, activeUser, depthMin, depthMax) => {
|
||||
document.addEventListener("alpine:init", () => {
|
||||
const defaultDepth = 2;
|
||||
|
||||
function getInitialDepth(prop) {
|
||||
// biome-ignore lint/correctness/noUndeclaredVariables: defined by script.js
|
||||
const value = Number.parseInt(initialUrlParams.get(prop));
|
||||
if (Number.isNaN(value) || value < depthMin || value > depthMax) {
|
||||
return defaultDepth;
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
Alpine.data("graph", () => ({
|
||||
loading: false,
|
||||
godfathersDepth: getInitialDepth("godfathersDepth"),
|
||||
godchildrenDepth: getInitialDepth("godchildrenDepth"),
|
||||
// biome-ignore lint/correctness/noUndeclaredVariables: defined by script.js
|
||||
reverse: initialUrlParams.get("reverse")?.toLowerCase?.() === "true",
|
||||
graph: undefined,
|
||||
graphData: {},
|
||||
|
||||
async init() {
|
||||
const delayedFetch = Alpine.debounce(async () => {
|
||||
await this.fetchGraphData();
|
||||
}, 100);
|
||||
for (const param of ["godfathersDepth", "godchildrenDepth"]) {
|
||||
this.$watch(param, async (value) => {
|
||||
if (value < depthMin || value > depthMax) {
|
||||
return;
|
||||
}
|
||||
// biome-ignore lint/correctness/noUndeclaredVariables: defined by script.js
|
||||
updateQueryString(param, value, History.REPLACE);
|
||||
await delayedFetch();
|
||||
});
|
||||
}
|
||||
this.$watch("reverse", async (value) => {
|
||||
// biome-ignore lint/correctness/noUndeclaredVariables: defined by script.js
|
||||
updateQueryString("reverse", value, History.REPLACE);
|
||||
await this.reverseGraph();
|
||||
});
|
||||
this.$watch("graphData", async () => {
|
||||
await this.generateGraph();
|
||||
if (this.reverse) {
|
||||
await this.reverseGraph();
|
||||
}
|
||||
});
|
||||
await this.fetchGraphData();
|
||||
},
|
||||
|
||||
screenshot() {
|
||||
const link = document.createElement("a");
|
||||
link.href = this.graph.jpg();
|
||||
link.download = interpolate(
|
||||
gettext("family_tree.%(extension)s"),
|
||||
{ extension: "jpg" },
|
||||
true,
|
||||
);
|
||||
document.body.appendChild(link);
|
||||
link.click();
|
||||
document.body.removeChild(link);
|
||||
},
|
||||
|
||||
reset() {
|
||||
this.reverse = false;
|
||||
this.godfathersDepth = defaultDepth;
|
||||
this.godchildrenDepth = defaultDepth;
|
||||
},
|
||||
|
||||
async reverseGraph() {
|
||||
this.graph.elements((el) => {
|
||||
el.position({ x: -el.position().x, y: -el.position().y });
|
||||
});
|
||||
this.graph.center(this.graph.elements());
|
||||
},
|
||||
|
||||
async fetchGraphData() {
|
||||
this.graphData = await getGraphData(
|
||||
apiUrl,
|
||||
this.godfathersDepth,
|
||||
this.godchildrenDepth,
|
||||
);
|
||||
},
|
||||
|
||||
async generateGraph() {
|
||||
this.loading = true;
|
||||
this.graph = await createGraph($(this.$refs.graph), this.graphData, activeUser);
|
||||
this.loading = false;
|
||||
},
|
||||
}));
|
||||
});
|
||||
};
|
||||
+1
-1
@@ -28,7 +28,7 @@ import { showSaveFilePicker } from "native-file-system-adapter";
|
||||
|
||||
/**
|
||||
* Load user picture page with a nice download bar
|
||||
* @param {String} Link to the api to fetch pictures from the user
|
||||
* @param {string} Url of the api endpoint to fetch pictures from the user
|
||||
**/
|
||||
window.loadPicturePage = (apiUrl) => {
|
||||
document.addEventListener("alpine:init", () => {
|
||||
@@ -7,13 +7,7 @@
|
||||
{%- endblock -%}
|
||||
|
||||
{% block additional_js %}
|
||||
<script src="{{ static("vendored/cytoscape/cytoscape.min.js") }}" defer></script>
|
||||
<script src="{{ static("vendored/cytoscape/cytoscape-cxtmenu.min.js") }}" defer></script>
|
||||
|
||||
<script src="{{ static("vendored/cytoscape/klay.min.js") }}" defer></script>
|
||||
<script src="{{ static("vendored/cytoscape/cytoscape-klay.min.js") }}" defer></script>
|
||||
|
||||
<script src="{{ static("user/js/family_graph.js") }}" defer></script>
|
||||
<script src="{{ static("webpack/user/family-graph-index.js") }}" defer></script>
|
||||
{% endblock %}
|
||||
|
||||
{% block title %}
|
||||
@@ -96,10 +90,14 @@
|
||||
</div>
|
||||
|
||||
<script>
|
||||
const apiUrl = "{{ api_url }}";
|
||||
const activeUser = "{{ object.id }}"
|
||||
const depthMin = {{ depth_min }};
|
||||
const depthMax = {{ depth_max }};
|
||||
window.addEventListener("DOMContentLoaded", () => {
|
||||
loadFamilyGraph(
|
||||
"{{ api_url }}",
|
||||
"{{ object.id }}",
|
||||
{{ depth_min }},
|
||||
{{ depth_max }},
|
||||
);
|
||||
})
|
||||
</script>
|
||||
{% endblock %}
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
{%- endblock -%}
|
||||
|
||||
{% block additional_js %}
|
||||
<script src="{{ static('webpack/users/pictures-index.js') }}" defer></script>
|
||||
<script src="{{ static('webpack/user/pictures-index.js') }}" defer></script>
|
||||
{% endblock %}
|
||||
|
||||
{% block title %}
|
||||
|
||||
Generated
+35
@@ -12,6 +12,9 @@
|
||||
"@fortawesome/fontawesome-free": "^6.6.0",
|
||||
"@zip.js/zip.js": "^2.7.52",
|
||||
"alpinejs": "^3.14.1",
|
||||
"cytoscape": "^3.30.2",
|
||||
"cytoscape-cxtmenu": "^3.5.0",
|
||||
"cytoscape-klay": "^3.1.4",
|
||||
"easymde": "^2.18.0",
|
||||
"glob": "^11.0.0",
|
||||
"jquery": "^3.7.1",
|
||||
@@ -3233,6 +3236,33 @@
|
||||
"integrity": "sha512-aylIc7Z9y4yzHYAJNuESG3hfhC+0Ibp/MAMiaOZgNv4pmEdFyfZhhhny4MNiAfWdBQ1RQ2mfDWmM1x8SvGyp8g==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/cytoscape": {
|
||||
"version": "3.30.2",
|
||||
"resolved": "https://registry.npmjs.org/cytoscape/-/cytoscape-3.30.2.tgz",
|
||||
"integrity": "sha512-oICxQsjW8uSaRmn4UK/jkczKOqTrVqt5/1WL0POiJUT2EKNc9STM4hYFHv917yu55aTBMFNRzymlJhVAiWPCxw==",
|
||||
"engines": {
|
||||
"node": ">=0.10"
|
||||
}
|
||||
},
|
||||
"node_modules/cytoscape-cxtmenu": {
|
||||
"version": "3.5.0",
|
||||
"resolved": "https://registry.npmjs.org/cytoscape-cxtmenu/-/cytoscape-cxtmenu-3.5.0.tgz",
|
||||
"integrity": "sha512-CoqgKAxvQhmHO5fEgJdBqqR2VjwK1dNkxehc2i0MUMqY0araA13z3oP/9KkprHp9Td++KlVBz6JnncNAD76T0Q==",
|
||||
"peerDependencies": {
|
||||
"cytoscape": "^3.2.0"
|
||||
}
|
||||
},
|
||||
"node_modules/cytoscape-klay": {
|
||||
"version": "3.1.4",
|
||||
"resolved": "https://registry.npmjs.org/cytoscape-klay/-/cytoscape-klay-3.1.4.tgz",
|
||||
"integrity": "sha512-VwPj0VR25GPfy6qXVQRi/MYlZM/zkdvRhHlgqbM//lSvstgM6fhp3ik/uM8Wr8nlhskfqz/M1fIDmR6UckbS2A==",
|
||||
"dependencies": {
|
||||
"klayjs": "^0.4.1"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"cytoscape": "^3.2.0"
|
||||
}
|
||||
},
|
||||
"node_modules/debug": {
|
||||
"version": "4.3.7",
|
||||
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz",
|
||||
@@ -3959,6 +3989,11 @@
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/klayjs": {
|
||||
"version": "0.4.1",
|
||||
"resolved": "https://registry.npmjs.org/klayjs/-/klayjs-0.4.1.tgz",
|
||||
"integrity": "sha512-WUNxuO7O79TEkxCj6OIaK5TJBkaWaR/IKNTakgV9PwDn+mrr63MLHed34AcE2yTaDntgO6l0zGFIzhcoTeroTA=="
|
||||
},
|
||||
"node_modules/lilconfig": {
|
||||
"version": "3.1.2",
|
||||
"resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-3.1.2.tgz",
|
||||
|
||||
@@ -31,6 +31,9 @@
|
||||
"@fortawesome/fontawesome-free": "^6.6.0",
|
||||
"@zip.js/zip.js": "^2.7.52",
|
||||
"alpinejs": "^3.14.1",
|
||||
"cytoscape": "^3.30.2",
|
||||
"cytoscape-cxtmenu": "^3.5.0",
|
||||
"cytoscape-klay": "^3.1.4",
|
||||
"easymde": "^2.18.0",
|
||||
"glob": "^11.0.0",
|
||||
"jquery": "^3.7.1",
|
||||
|
||||
@@ -740,10 +740,6 @@ if SENTRY_DSN:
|
||||
SITH_FRONT_DEP_VERSIONS = {
|
||||
"https://github.com/chartjs/Chart.js/": "2.6.0",
|
||||
"https://github.com/getsentry/sentry-javascript/": "8.26.0",
|
||||
"https://github.com/cytoscape/cytoscape.js": "3.30.2 ",
|
||||
"https://github.com/cytoscape/cytoscape.js-cxtmenu": "3.5.0",
|
||||
"https://github.com/cytoscape/cytoscape.js-klay": "3.1.4",
|
||||
"https://github.com/kieler/klayjs": "0.4.1", # Deprecated, elk should be used but cytoscape-elk is broken
|
||||
"https://github.com/mrdoob/three.js/": "r148",
|
||||
"https://github.com/vasturiano/three-spritetext": "1.6.5",
|
||||
"https://github.com/vasturiano/3d-force-graph/": "1.70.19",
|
||||
|
||||
Reference in new issue
Block a user