На прошлой неделе мы видели Sigma.js , и, как и было обещано, здесь представлена визуализация графиков с Three.js и Neo4j . Three.js — это легкая 3D-библиотека, написанная г-ном Дубом и небольшой группой авторов.
То, что вы можете сделать с Three.js, поразительно, и моя небольшая демонстрация здесь не дает справедливости, но, тем не менее, я покажу вам, как это сделать.
Нам нужно передать узлы и отношения в Three.js, один из способов, которым мы можем легко это сделать, — с помощью камня Gon , так как мы используем sinatra, мы будем использовать специальный камень gon-sinatra .
class App < Sinatra::Base
register Gon::Sinatra
def nodes
neo = Neography::Rest.new
cypher_query = " START node = node:nodes_index(type='User')"
cypher_query << " RETURN ID(node), node"
neo.execute_query(cypher_query)["data"].collect{|n| {"id" => n[0]}.merge(n[1]["data"])}
end
def edges
neo = Neography::Rest.new
cypher_query = " START source = node:nodes_index(type='User')"
cypher_query << " MATCH source -[rel]-> target"
cypher_query << " RETURN ID(rel), ID(source), ID(target)"
neo.execute_query(cypher_query)["data"].collect{|n| {"id" => n[0], "source" => n[1], "target" => n[2]} }
end
get '/' do
neo = Neography::Rest.new
gon.nodes = nodes
gon.edges = edges
erb :index
end
end
На наш взгляд, мы добавим «include_gon», который связывает наши узлы и ребра с нашей HTML-страницей.
<!doctype html> <html lang="en"> <head> <title>Three.js and Neo4j</title> <%= include_gon %> <meta charset="utf-8"> <script type="text/javascript" src="Three.js"></script> <link type="text/css" rel="stylesheet" href="neo_three.css"/> </head> <body> <script type="text/javascript" src="neo_three.js"></script> </body> </html>
Если вы просмотрите источник index.html, вы увидите наши узлы и ребра.
window.gon = {};
gon.nodes=[{"id":1,
"rotation_x":5.061454830783556,
"name":"zfbushqe",
"position_y":256,
"position_x":658,
"position_z":577,
"rotation_y":3.543018381548489},
{"id":2,
"rotation_x":4.572762640225143,
"name":"afntayhh",
"position_y":-22,
"position_x":510,
"position_z":404,
"rotation_y":2.2689280275926285}
...
gon.edges=[{"id":3,"source":1,"target":198},
{"id":2,"source":1,"target":39},
{"id":1,"source":1,"target":21}
...
]
Чтобы использовать Three.js, нам нужно создать камеру, сцену и выбрать рендер для использования.
camera = new THREE.PerspectiveCamera( 75, window.innerWidth / window.innerHeight, 1, 10000 ); camera.position.z = 100; scene = new THREE.Scene(); scene.add( camera ); renderer = new THREE.CanvasRenderer(); renderer.setSize( window.innerWidth, window.innerHeight ); container.appendChild( renderer.domElement );
Для создания наших узлов мы будем использовать сферы и использовать обычный материал. Мы возьмем узлы из gon и используем их свойства для позиционирования и установки ориентации наших сфер.
var geometry = new THREE.SphereGeometry( 50, 8, 7, false );
var material = new THREE.MeshNormalMaterial();
group = new THREE.Object3D();
for (n in gon.nodes) {
var mesh = new THREE.Mesh( geometry, material );
mesh.position.x = gon.nodes[n].position_x;
mesh.position.y = gon.nodes[n].position_y;
mesh.position.z = gon.nodes[n].position_z;
mesh.rotation.x = gon.nodes[n].rotation_x;
mesh.rotation.y = gon.nodes[n].rotation_y;
mesh.matrixAutoUpdate = false;
mesh.updateMatrix();
group.add( mesh );
}
scene.add( group );
Для наших ребер мы создадим простые линии случайных цветов между исходным и целевым узлами.
for (n in gon.edges) {
var line_segment = new THREE.Geometry();
line_segment.vertices.push( new THREE.Vertex( group.children[gon.edges[n].source - 1].position ) );
line_segment.vertices.push( new THREE.Vertex( group.children[gon.edges[n].target - 1].position ) );
var line = new THREE.Line( line_segment,
new THREE.LineBasicMaterial( { color: Math.random() * 0xffffff,
opacity: 0.5 } ) );
scene.add(line)
}
Мы будем анимировать нашу визуализацию, визуализируя сцену и управляя камерой с помощью мыши.
document.addEventListener( 'mousemove', onDocumentMouseMove, false );
function onDocumentMouseMove(event) {
mouseX = event.clientX - windowHalfX;
mouseY = event.clientY - windowHalfY;
}
function animate() {
requestAnimationFrame( animate );
render();
}
function render() {
camera.position.x += ( mouseX - camera.position.x ) * .05;
camera.position.y += ( - mouseY + 200 - camera.position.y ) * .05;
camera.lookAt( scene.position );
renderer.render( scene, camera );
}
Я собираюсь пропустить создание графика, но весь код, как обычно, доступен на github , и вам наверняка захочется увидеть это вживую на Heroku .
Если вы хотите узнать больше о Three.js, ознакомьтесь с этим руководством и этими видео .
