Appearance
Neo4j Cypher
This exame shows how to connect to a neo4j database, run cypher queries and display the results in Ogma.
This example actually uses pre-recorded responses of a neo4j@v3.0.4
server. To use this example with your database, omit the stub file and follow the instructions the example code.
Use neo4j javascript driver to create a driver and a session.
Then use Ogma's parse.neo4j()
function to parse the results into Ogma's RawGraph
format.
Double click on a node to expand the graph.
js
import Ogma from '@linkurious/ogma';
// this is a stub using pre-recorded server responses, don't use it
import * as neo4j from './neo4j-stub';
// for the actual server connection, use next line
// import neo4j from 'neo4j-driver';
// highlight the Cypher query
hljs.initHighlightingOnLoad();
const ogma = new Ogma({
container: 'graph-container'
});
// Create a connection to the Neo4j database.
// change this URL to your local Neo4j database instance
const driver = neo4j.driver(
'bolt://localhost:7687',
neo4j.auth.basic('example', 'b.SKbqdJ4W59Zk.dQqSZRuJ1NoxwWcz'),
{ encrypted: true } // remove this to run it locally
);
const session = driver.session();
const toggleLoading = () => {
const el = document.querySelector('#info');
const enable = el.style.display;
el.style.display = enable === 'block' ? 'none' : 'block';
};
const getStartTemplate = () =>
['MATCH (n)', 'OPTIONAL MATCH (n)-[r]-(m)', 'RETURN n,r,m', 'LIMIT 5'].join(
'\n'
);
const getExpandQuery = id =>
[
'MATCH (n)-[r]-(m)',
'WHERE id(n) = ' + id,
'RETURN n,r,m',
'LIMIT 100'
].join('\n');
const updateCypherQuery = query => {
const codeBlock = document.querySelector('#query-text');
codeBlock.innerText = query;
hljs.highlightBlock(codeBlock);
};
const res = {};
const sendQuery = id => {
const query = id ? getExpandQuery(id) : getStartTemplate();
toggleLoading();
updateCypherQuery(query);
return session
.run(query)
.then(result => {
res[query] = JSON.stringify(result);
return Ogma.parse.neo4j(result);
})
.then(graph => {
toggleLoading();
return ogma.addGraph(graph);
})
.then(() => layout());
};
const layout = () =>
ogma.layouts.forceLink({
duration: 550,
locate: { padding: 80 }
});
// Define what to use as node and edge captions.
ogma.styles.addEdgeRule({
text: {
content: e => e.getData('neo4jType')
},
color: e => {
const labels = e.getData('neo4jType');
if (labels.includes('ACTED_IN')) {
return '#22b455';
}
if (labels.includes('DIRECTED')) {
return '#80ce87';
}
if (labels.includes('PRODUCED')) {
return '#92e5a1';
}
}
});
ogma.styles.addNodeRule({
text: {
content: n => {
if (n.getData('neo4jLabels').includes('Movie')) {
return n.getData('neo4jProperties.title');
}
if (n.getData('neo4jLabels').includes('Person')) {
return n.getData('neo4jProperties.name');
}
}
},
icon: {
content: n => {
if (n.getData('neo4jLabels').includes('Movie')) {
return '\uf008';
}
if (n.getData('neo4jLabels').includes('Person')) {
return '\uf007';
}
},
font: 'Font Awesome 5 Free',
color: 'black',
minVisibleSize: 0
},
outerStroke: {
color: '#204829',
width: 2
},
color: 'white'
});
ogma.events.on('doubleclick', evt => {
if (evt.target && evt.target.isNode) {
sendQuery(evt.target.getId());
}
});
document.querySelector('#layout').addEventListener('click', evt => {
evt.preventDefault();
layout();
});
sendQuery();
// close the session before unloading the page
document.addEventListener('onbeforeunload', evt => session.close());
html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<script
src="https://cdn.jsdelivr.net/npm/neo4j-driver@4.0.1/lib/browser/neo4j-web.min.js"></script>
<link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.11.2/css/solid.min.css" rel="stylesheet" />
<script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/10.7.2/highlight.min.js">
</script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/10.7.2/styles/default.min.css"/>
<script type="text/javascript"
src="https://unpkg.com/highlightjs-cypher/dist/cypher.min.js">
</script>
<link type="text/css" rel="stylesheet" href="styles.css">
</head>
<body>
<div id="graph-container"></div>
<div class="toolbar">
<h3>Current cypher query</h3>
<pre><code class="cypher" id="query-text"></code></pre>
<div class="controls">
<button id="layout" class="btn menu">Layout</button>
</div>
</div>
<div id="info">loading...</div>
<script src="index.js"></script>
</body>
</html>
css
#graph-container {
top: 0;
bottom: 0;
left: 0;
right: 0;
position: absolute;
margin: 0;
overflow: hidden;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
-o-user-select: none;
user-select: none;
}
#info {
position: absolute;
color: #fff;
background: #141229;
font-size: 12px;
font-family: monospace;
padding: 5px;
top: 0;
left: 0;
white-space: pre;
}
.toolbar {
display: block;
position: absolute;
top: 20px;
right: 20px;
padding: 10px;
box-shadow: 0 1px 5px rgba(0, 0, 0, 0.65);
border-radius: 4px;
background: #ffffff;
color: #222222;
font-weight: 300;
min-width: 200px;
}
.toolbar h3 {
display: block;
font-weight: 300;
border-bottom: 1px solid #ddd;
color: #606060;
font-size: 1rem;
font-family: Arial, Helvetica, sans-serif;
}
.controls {
text-align: center;
margin-top: 5px;
}
.btn {
padding: 6px 8px;
background-color: white;
cursor: pointer;
font-size: 18px;
border: none;
border-radius: 5px;
outline: none;
}
.btn:hover {
color: #333;
background-color: #e6e6e6;
}
.menu {
border: 1px solid #ddd;
width: 80%;
font-size: 14px;
margin-top: 10px;
}
js
// * Neo4j driver stub *
//
// Do not use this file! It's only purpose is
// to make this demo work smoothly with a static
// pre-recorded server responses
export const auth = {
basic(db, password) {
return new BasicAuth(db, password);
}
};
class BasicAuth {
constructor(db, password) {
}
}
class Session {
constructor(driver) {
this._driver = driver;
this._data = null;
this._ready = fetch('files/movies-neo4j.json')
.then(r => r.json())
.then(responses => this._data = responses)
.then(() => console.log('data loaded'));
}
run(query) {
return this._ready
.then(() => this._data[query] || '{ "records": [] }')
}
}
class Driver {
session() {
return new Session(this);
}
close() {
return Promise.resolve();
}
}
export const driver = (url, auth) => new Driver(url, auth);