|
|
|
@ -22,6 +22,9 @@ |
|
|
|
|
<!-- still experimenting, see webdav.html --> |
|
|
|
|
<script src='dependencies/webdav.js'></script> |
|
|
|
|
|
|
|
|
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/cytoscape/3.8.2/cytoscape.min.js"></script> |
|
|
|
|
<script src="https://cytoscape.org/cytoscape.js-euler/cytoscape-euler.js"></script> |
|
|
|
|
|
|
|
|
|
<!-- replacing with local copies as CDNs are like unpkg tend to be slow |
|
|
|
|
<script type="module" src="https://unpkg.com/immers-client/dist/destination.bundle.js"></script> |
|
|
|
|
<script src="https://aframe.io/releases/1.3.0/aframe.min.js"></script> |
|
|
|
@ -1965,6 +1968,121 @@ function rescalePlace(scale = 10, yoffset=-1){ |
|
|
|
|
} ) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// from https://glitch.com/edit/#!/zen-pim?path=graph-cyto-headless.html |
|
|
|
|
// see also https://observablehq.com/@utopiah/d3-pim-graph |
|
|
|
|
// motivated by https://these.arthurperret.fr/chapitre-4.html#cosmographe-et-cosmoscope |
|
|
|
|
|
|
|
|
|
const cytoJson = "https://vatelier.benetou.fr/MyDemo/newtooling/wiki_graph_cyto.json" |
|
|
|
|
|
|
|
|
|
var cy |
|
|
|
|
var jsonLoaded |
|
|
|
|
|
|
|
|
|
fetch(cytoJson) |
|
|
|
|
.then(function (response) { |
|
|
|
|
return response.json(); |
|
|
|
|
}) |
|
|
|
|
.then(function (json) { |
|
|
|
|
// take nodes from wiki.Nodes then construct an array in elements for cytoscape format |
|
|
|
|
// or directly from JSON http://js.cytoscape.org/#notation/elements-json |
|
|
|
|
jsonLoaded = json |
|
|
|
|
startCytoWithData(json) |
|
|
|
|
}) |
|
|
|
|
.catch(function (err) { |
|
|
|
|
console.log(err); |
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
// should instead directly use https://vatelier.net/MyDemo/newtooling/wiki_graph_cyto.json |
|
|
|
|
// generated from https://vatelier.net/MyDemo/newtooling/build_graph_cytograph.js |
|
|
|
|
// cf instead http://js.cytoscape.org/demos/tokyo-railways/tokyo-railways.json more detail |
|
|
|
|
// with details on how to load the JSON |
|
|
|
|
|
|
|
|
|
function runCytoAnalysis(){ |
|
|
|
|
console.log('----------------- network analysis started --------------') |
|
|
|
|
if (!cy.nodes('[id = "Analysis.Analysis"]').length) { |
|
|
|
|
console.warn('Wrong dataset, cancelling') |
|
|
|
|
return |
|
|
|
|
} |
|
|
|
|
// example of queries |
|
|
|
|
var aStar = cy.elements().aStar({ root: '[id = "Analysis.Analysis"]', goal: '[id = "Analysis.CostsAndBenefitsOfSocietalMembership"]' }) |
|
|
|
|
if ( aStar.path){ |
|
|
|
|
console.log("Path from Analysis.Analysis to Analysis.CostsAndBenefitsOfSocietalMembership", aStar.path.edges() , aStar.path.nodes() ) |
|
|
|
|
aStar.path.select() |
|
|
|
|
} |
|
|
|
|
console.log( cy.nodes('[id = "Analysis.Analysis"]').neighborhood() ) |
|
|
|
|
before = Date.now() |
|
|
|
|
var bc = cy.elements().bc() |
|
|
|
|
after = Date.now() |
|
|
|
|
console.log("took ", after-before, "ms to run.") |
|
|
|
|
console.log( 'bc of j: ' + bc.betweenness('[id = "Analysis.Analysis"]') ) |
|
|
|
|
console.log( cy.nodes('[id = "Analysis.CostsAndBenefitsOfSocietalMembership"]').neighborhood() ) |
|
|
|
|
//no need to run cy.elements().bc() again. It's done once for the whole graph. |
|
|
|
|
console.log( 'bc of j: ' + bc.betweenness('[id = "Analysis.CostsAndBenefitsOfSocietalMembership"]') ) |
|
|
|
|
console.log('----------------- network analysis done -----------------') |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
function startCytoWithData(json){ |
|
|
|
|
cy = cytoscape({ |
|
|
|
|
headless:true, |
|
|
|
|
elements: json.elements |
|
|
|
|
}) |
|
|
|
|
|
|
|
|
|
//runCytoAnalysis() //quite demanding, skipped for now. |
|
|
|
|
|
|
|
|
|
let defaults = { |
|
|
|
|
name: 'euler', |
|
|
|
|
springLength: edge => 80, |
|
|
|
|
springCoeff: edge => 0.0008, |
|
|
|
|
mass: node => 4, |
|
|
|
|
gravity: -1.2, |
|
|
|
|
pull: 0.001, |
|
|
|
|
theta: 0.666, |
|
|
|
|
dragCoeff: 0.02, |
|
|
|
|
movementThreshold: 1, |
|
|
|
|
timeStep: 20, |
|
|
|
|
refresh: 10, |
|
|
|
|
animate: true, |
|
|
|
|
animationDuration: undefined, |
|
|
|
|
animationEasing: undefined, |
|
|
|
|
maxIterations: 1000, |
|
|
|
|
maxSimulationTime: 4000, |
|
|
|
|
ungrabifyWhileSimulating: false, |
|
|
|
|
fit: true, |
|
|
|
|
padding: 30, |
|
|
|
|
// Constrain layout bounds with one of |
|
|
|
|
// - { x1, y1, x2, y2 } |
|
|
|
|
// - { x1, y1, w, h } |
|
|
|
|
// - undefined / null : Unconstrained |
|
|
|
|
boundingBox: undefined, |
|
|
|
|
|
|
|
|
|
// Layout event callbacks; equivalent to `layout.one('layoutready', callback)` for example |
|
|
|
|
ready: function(){ console.log("graph ready", cy.json()) }, // on layoutready |
|
|
|
|
stop: stableGraph(), // on layoutstop |
|
|
|
|
randomize: false |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
// disabled for tests |
|
|
|
|
//cy.layout( defaults ).run(); // too demanding for the entire graph, should limit to a subset |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
function stableGraph(){ |
|
|
|
|
var exportableJSON = cy.json() |
|
|
|
|
console.log( 'exportable JSON', exportableJSON ); |
|
|
|
|
// not actually stable! |
|
|
|
|
// still could be used as a form of caching BUT... would take into account new nodes added since |
|
|
|
|
|
|
|
|
|
var node = "ReadingNotes.ApocalypticAI" |
|
|
|
|
if (!cy.nodes('[id = "'+node+'"]').length) { |
|
|
|
|
console.warn('Wrong dataset, cancelling') |
|
|
|
|
return |
|
|
|
|
} |
|
|
|
|
console.log('should add/update AFrame nodes e.g', cy.elements('[id = "'+node+'"]').position()) |
|
|
|
|
console.log('could add all the nodes then their links with proper attributes in order to do select() after') |
|
|
|
|
// using e.g. cy.nodes().forEach( n => console.log(n.data(), n.position() ) ) |
|
|
|
|
// cy.edges().forEach( e => console.log(e.data(), e.sourceEndpoint(), e.targetEndpoint() )) |
|
|
|
|
// warning, very costly! |
|
|
|
|
// run on entire wiki though whereas previous D3 instance limited to 10 pages and their targets |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// could change model opacity based on hand position, fading out when within a (very small here) safe space |
|
|
|
|
</script> |
|
|
|
|
<div id="observablehq-key"> |
|
|
|
|