На прошлой неделе мы видели 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, ознакомьтесь с этим руководством и этими видео .