diff --git a/galaxy/templates/galaxy/user.jinja b/galaxy/templates/galaxy/user.jinja index 574cc824..38abb6de 100644 --- a/galaxy/templates/galaxy/user.jinja +++ b/galaxy/templates/galaxy/user.jinja @@ -7,9 +7,9 @@ {% block content %} {% if object.current_star %}
-
+
-
+

Reset on {{ object.get_display_name() }}

Self score: {{ object.current_star.mass }}

@@ -58,9 +58,31 @@ return Graph.graphData().nodes.find(n => n.id === id); } + function get_links_from_node_id(id) { + return Graph.graphData().links.filter(l => l.source.id === id || l.target.id === id); + } + function focus_node(node) { + highlightNodes.clear(); + highlightLinks.clear(); + + hoverNode = node || null; + if (node) { // collect neighbors and links for highlighting + get_links_from_node_id(node.id).forEach(link => { + highlightLinks.add(link); + highlightNodes.add(link.source); + highlightNodes.add(link.target); + }); + } + + // refresh node and link display + Graph + .nodeThreeObject(Graph.nodeThreeObject()) + .linkWidth(Graph.linkWidth()) + .linkDirectionalParticles(Graph.linkDirectionalParticles()); + // Aim at node from outside it - const distance = 200; + const distance = 42; const distRatio = 1 + distance/Math.hypot(node.x, node.y, node.z); const newPos = node.x || node.y || node.z @@ -74,25 +96,44 @@ ); } + const highlightNodes = new Set(); + const highlightLinks = new Set(); + let hoverNode = null; + document.addEventListener("DOMContentLoaded", () => { + var graph_div = document.getElementById('3d-graph'); Graph = ForceGraph3D(); - Graph(document.getElementById('3d-graph')); + Graph(graph_div); Graph .jsonUrl('{{ url("galaxy:data") }}') - .width(1000) - .height(700) - .nodeAutoColorBy('id') - .nodeLabel(node => `${node.name}`) - .onNodeClick(node => focus_node(node)) - .linkDirectionalParticles(3) - .linkDirectionalParticleWidth(0.8) - .linkDirectionalParticleSpeed(0.006) + .width(graph_div.parentElement.clientWidth > 1200 ? 1200 : graph_div.parentElement.clientWidth) // Not perfect at all. JS-fu master from the future, please fix this :-) + .height(1000) + .enableNodeDrag(false) // allow easier navigation + .onNodeClick(node => { + camera = Graph.cameraPosition(); + var distance = Math.sqrt(Math.pow(node.x - camera.x, 2) + Math.pow(node.y - camera.y, 2) + Math.pow(node.z - camera.z, 2)) + if (distance < 120 || highlightNodes.has(node)) { + focus_node(node); + } + }) + .linkWidth(link => highlightLinks.has(link) ? 0.4 : 0.0) + .linkColor(link => highlightLinks.has(link) ? 'rgba(255,160,0,1)' : 'rgba(128,255,255,0.6)') + .linkVisibility(link => highlightLinks.has(link)) + .nodeVisibility(node => highlightNodes.has(node) || node.mass > 4) + // .linkDirectionalParticles(link => highlightLinks.has(link) ? 3 : 1) // kinda buggy for now, and slows this a bit, but would be great to help visualize lanes + .linkDirectionalParticleWidth(0.2) + .linkDirectionalParticleSpeed(-0.006) .nodeThreeObject(node => { const sprite = new SpriteText(node.name); sprite.material.depthWrite = false; // make sprite background transparent - sprite.color = node.color; - sprite.textHeight = 5; + sprite.color = highlightNodes.has(node) ? node === hoverNode ? 'rgba(200,0,0,1)' : 'rgba(255,160,0,0.8)' : 'rgba(0,255,255,0.2)'; + sprite.textHeight = 2; + sprite.center = new THREE.Vector2(1.2, 0.5); return sprite; + }) + .onEngineStop( () => { + focus_node(get_node_from_id({{ object.id }})); + Graph.onEngineStop(() => {}); // don't call ourselves in a loop while moving the focus }); // Set distance between stars @@ -103,9 +144,6 @@ Graph.d3Force('positionX', d3.forceX().strength(node => { return 1 - (1 / node.mass); })); Graph.d3Force('positionY', d3.forceY().strength(node => { return 1 - (1 / node.mass); })); Graph.d3Force('positionZ', d3.forceZ().strength(node => { return 1 - (1 / node.mass); })); - - // Focus current user - setTimeout(() => focus_node(get_node_from_id({{ object.id }})), 1000); }) {% endblock %}