提交 6b9d77f6 authored 作者: tb53863844's avatar tb53863844

知识图谱组件

上级 acab7121
import React from 'react'
import Neo4jD3 from '@/webPublic/one_stop_public/utils/Neo4jD3'
import UUID from 'react-native-uuid';
export default class Neo4jD3Com extends React.Component {
uid=UUID.v4()
triggerChange = (changedValue) => {
// Should provide an event to pass value to Form.
const onChange = this.props.onChange;
if (onChange) {
onChange( changedValue);
}
}
data
componentWillReceiveProps(nextProps) {
// Should be a controlled component.
if ('option' in nextProps&&nextProps.option&&nextProps.option.neo4jData) {
if(this.neo4jd3==null){
this.data=nextProps.option.neo4jData
this.init(nextProps.option.neo4jData)
}else{
if(JSON.stringify(this.data)!=JSON.stringify(nextProps.option.neo4jData)){
this.neo4jd3.updateWithD3Data(nextProps.option.neo4jData)
this.data=nextProps.option.neo4jData
}
}
}
}
changePos=(obj)=>{
if (!('value' in this.props)) {
this.setState({...obj});
}
this.triggerChange({...obj});
}
neo4jd3
init=(neo4jData)=>{
/* const x = [
{
"p": {
"start": {
"identity": 548,
"labels": [
"Actor"
],
"properties": {
"name": "Carrie-Anne Moss",
"personId": "carrieanne"
}
},
"end": {
"identity": 0,
"labels": [
"Movie"
],
"properties": {
"movieId": "tt0133093",
"title": "The Matrix",
"year": 1999
}
},
"segments": [
{
"start": {
"identity": 548,
"labels": [
"Actor"
],
"properties": {
"name": "Carrie-Anne Moss",
"personId": "carrieanne"
}
},
"relationship": {
"identity": 6,
"start": 548,
"end": 0,
"type": "ACTED_IN",
"properties": {
"role": "Trinity"
}
},
"end": {
"identity": 0,
"labels": [
"Movie"
],
"properties": {
"movieId": "tt0133093",
"title": "The Matrix",
"year": 1999
}
}
}
],
"length": 1.0
}
},
{
"p": {
"start": {
"identity": 547,
"labels": [
"Actor"
],
"properties": {
"name": "Laurence Fishburne",
"personId": "laurence"
}
},
"end": {
"identity": 0,
"labels": [
"Movie"
],
"properties": {
"movieId": "tt0133093",
"title": "The Matrix",
"year": 1999
}
},
"segments": [
{
"start": {
"identity": 547,
"labels": [
"Actor"
],
"properties": {
"name": "Laurence Fishburne",
"personId": "laurence"
}
},
"relationship": {
"identity": 3,
"start": 547,
"end": 0,
"type": "ACTED_IN",
"properties": {
"role": "Morpheus"
}
},
"end": {
"identity": 0,
"labels": [
"Movie"
],
"properties": {
"movieId": "tt0133093",
"title": "The Matrix",
"year": 1999
}
}
}
],
"length": 1.0
}
},
{
"p": {
"start": {
"identity": 546,
"labels": [
"Actor"
],
"properties": {
"name": "Keanu Reeves",
"personId": "keanu"
}
},
"end": {
"identity": 0,
"labels": [
"Movie"
],
"properties": {
"movieId": "tt0133093",
"title": "The Matrix",
"year": 1999
}
},
"segments": [
{
"start": {
"identity": 546,
"labels": [
"Actor"
],
"properties": {
"name": "Keanu Reeves",
"personId": "keanu"
}
},
"relationship": {
"identity": 0,
"start": 546,
"end": 0,
"type": "ACTED_IN",
"properties": {
"role": "Neo"
}
},
"end": {
"identity": 0,
"labels": [
"Movie"
],
"properties": {
"movieId": "tt0133093",
"title": "The Matrix",
"year": 1999
}
}
}
],
"length": 1.0
}
},
{
"p": {
"start": {
"identity": 548,
"labels": [
"Actor"
],
"properties": {
"name": "Carrie-Anne Moss",
"personId": "carrieanne"
}
},
"end": {
"identity": 1,
"labels": [
"Movie",
"Sequel"
],
"properties": {
"movieId": "tt0234215",
"title": "The Matrix Reloaded",
"year": 2003
}
},
"segments": [
{
"start": {
"identity": 548,
"labels": [
"Actor"
],
"properties": {
"name": "Carrie-Anne Moss",
"personId": "carrieanne"
}
},
"relationship": {
"identity": 7,
"start": 548,
"end": 1,
"type": "ACTED_IN",
"properties": {
"role": "Trinity"
}
},
"end": {
"identity": 1,
"labels": [
"Movie",
"Sequel"
],
"properties": {
"movieId": "tt0234215",
"title": "The Matrix Reloaded",
"year": 2003
}
}
}
],
"length": 1.0
}
},
{
"p": {
"start": {
"identity": 547,
"labels": [
"Actor"
],
"properties": {
"name": "Laurence Fishburne",
"personId": "laurence"
}
},
"end": {
"identity": 1,
"labels": [
"Movie",
"Sequel"
],
"properties": {
"movieId": "tt0234215",
"title": "The Matrix Reloaded",
"year": 2003
}
},
"segments": [
{
"start": {
"identity": 547,
"labels": [
"Actor"
],
"properties": {
"name": "Laurence Fishburne",
"personId": "laurence"
}
},
"relationship": {
"identity": 4,
"start": 547,
"end": 1,
"type": "ACTED_IN",
"properties": {
"role": "Morpheus"
}
},
"end": {
"identity": 1,
"labels": [
"Movie",
"Sequel"
],
"properties": {
"movieId": "tt0234215",
"title": "The Matrix Reloaded",
"year": 2003
}
}
}
],
"length": 1.0
}
},
{
"p": {
"start": {
"identity": 546,
"labels": [
"Actor"
],
"properties": {
"name": "Keanu Reeves",
"personId": "keanu"
}
},
"end": {
"identity": 1,
"labels": [
"Movie",
"Sequel"
],
"properties": {
"movieId": "tt0234215",
"title": "The Matrix Reloaded",
"year": 2003
}
},
"segments": [
{
"start": {
"identity": 546,
"labels": [
"Actor"
],
"properties": {
"name": "Keanu Reeves",
"personId": "keanu"
}
},
"relationship": {
"identity": 1,
"start": 546,
"end": 1,
"type": "ACTED_IN",
"properties": {
"role": "Neo"
}
},
"end": {
"identity": 1,
"labels": [
"Movie",
"Sequel"
],
"properties": {
"movieId": "tt0234215",
"title": "The Matrix Reloaded",
"year": 2003
}
}
}
],
"length": 1.0
}
},
{
"p": {
"start": {
"identity": 548,
"labels": [
"Actor"
],
"properties": {
"name": "Carrie-Anne Moss",
"personId": "carrieanne"
}
},
"end": {
"identity": 2,
"labels": [
"Movie",
"Sequel"
],
"properties": {
"movieId": "tt0242653",
"title": "The Matrix Revolutions",
"year": 2003
}
},
"segments": [
{
"start": {
"identity": 548,
"labels": [
"Actor"
],
"properties": {
"name": "Carrie-Anne Moss",
"personId": "carrieanne"
}
},
"relationship": {
"identity": 8,
"start": 548,
"end": 2,
"type": "ACTED_IN",
"properties": {
"role": "Trinity"
}
},
"end": {
"identity": 2,
"labels": [
"Movie",
"Sequel"
],
"properties": {
"movieId": "tt0242653",
"title": "The Matrix Revolutions",
"year": 2003
}
}
}
],
"length": 1.0
}
},
{
"p": {
"start": {
"identity": 547,
"labels": [
"Actor"
],
"properties": {
"name": "Laurence Fishburne",
"personId": "laurence"
}
},
"end": {
"identity": 2,
"labels": [
"Movie",
"Sequel"
],
"properties": {
"movieId": "tt0242653",
"title": "The Matrix Revolutions",
"year": 2003
}
},
"segments": [
{
"start": {
"identity": 547,
"labels": [
"Actor"
],
"properties": {
"name": "Laurence Fishburne",
"personId": "laurence"
}
},
"relationship": {
"identity": 5,
"start": 547,
"end": 2,
"type": "ACTED_IN",
"properties": {
"role": "Morpheus"
}
},
"end": {
"identity": 2,
"labels": [
"Movie",
"Sequel"
],
"properties": {
"movieId": "tt0242653",
"title": "The Matrix Revolutions",
"year": 2003
}
}
}
],
"length": 1.0
}
},
{
"p": {
"start": {
"identity": 546,
"labels": [
"Actor"
],
"properties": {
"name": "Keanu Reeves",
"personId": "keanu"
}
},
"end": {
"identity": 2,
"labels": [
"Movie",
"Sequel"
],
"properties": {
"movieId": "tt0242653",
"title": "The Matrix Revolutions",
"year": 2003
}
},
"segments": [
{
"start": {
"identity": 546,
"labels": [
"Actor"
],
"properties": {
"name": "Keanu Reeves",
"personId": "keanu"
}
},
"relationship": {
"identity": 2,
"start": 546,
"end": 2,
"type": "ACTED_IN",
"properties": {
"role": "Neo"
}
},
"end": {
"identity": 2,
"labels": [
"Movie",
"Sequel"
],
"properties": {
"movieId": "tt0242653",
"title": "The Matrix Revolutions",
"year": 2003
}
}
}
],
"length": 1.0
}
}
]
var graph = eval(x);
console.log(JSON.stringify(graph))
let nodes =[];
let links = []; // 存放节点和关系
let nodeSet = []; // 存放去重后nodes的id
for (let item of graph) {
// console.log(item.p.start instanceof Array)
// console.log(item.p)
// 重新更改data格式
if(nodeSet.indexOf(item.p.start.identity) == -1){
nodeSet.push(item.p.start.identity)
nodes.push({
id: item.p.start.identity,
labels: item.p.start.labels,
properties: item.p.start.properties
})
}
if(nodeSet.indexOf(item.p.end.identity) == -1){
nodeSet.push(item.p.end.identity)
nodes.push({
id: item.p.end.identity,
labels: item.p.end.labels,
properties: item.p.end.properties
})
}
links.push({
source: item.p.segments[0].relationship.start,
target: item.p.segments[0].relationship.end,
type: item.p.segments[0].relationship.type,
properties: item.p.segments[0].relationship.properties
})
}
console.log(nodes)
console.log(links) */
this.neo4jd3 = new Neo4jD3 ('#id_'+this.uid, {
highlight: [
{
class: 'Project',
property: 'name',
value: 'neo4jd3'
}, {
class: 'User',
property: 'userId',
value: 'eisman'
}
],
icons: {
// 'Address': 'home',
'Api': 'gear',
// 'BirthDate': 'birthday-cake',
'Cookie': 'paw',
// 'CreditCard': 'credit-card',
// 'Device': 'laptop',
'Email': 'at',
'Git': 'git',
'Github': 'github',
'Google': 'google',
// 'icons': 'font-awesome',
'Ip': 'map-marker',
'Issues': 'exclamation-circle',
'Language': 'language',
'Options': 'sliders',
'Password': 'lock',
'Phone': 'phone',
'Project': 'folder-open',
'SecurityChallengeAnswer': 'commenting',
'User': 'user',
'zoomFit': 'arrows-alt',
'zoomIn': 'search-plus',
'zoomOut': 'search-minus'
},
images: {
'Address': 'img/twemoji/1f3e0.svg',
// 'Api': 'img/twemoji/1f527.svg',
'BirthDate': 'img/twemoji/1f382.svg',
'Cookie': 'img/twemoji/1f36a.svg',
'CreditCard': 'img/twemoji/1f4b3.svg',
'Device': 'img/twemoji/1f4bb.svg',
'Email': 'img/twemoji/2709.svg',
'Git': 'img/twemoji/1f5c3.svg',
'Github': 'img/twemoji/1f5c4.svg',
'icons': 'img/twemoji/1f38f.svg',
'Ip': 'img/twemoji/1f4cd.svg',
'Issues': 'img/twemoji/1f4a9.svg',
'Language': 'img/twemoji/1f1f1-1f1f7.svg',
'Options': 'img/twemoji/2699.svg',
'Password': 'img/twemoji/1f511.svg',
// 'Phone': 'img/twemoji/1f4de.svg',
'Project': 'img/twemoji/2198.svg',
'Project|name|neo4jd3': 'img/twemoji/2196.svg',
// 'SecurityChallengeAnswer': 'img/twemoji/1f4ac.svg',
'User': 'img/twemoji/1f600.svg'
// 'zoomFit': 'img/twemoji/2194.svg',
// 'zoomIn': 'img/twemoji/1f50d.svg',
// 'zoomOut': 'img/twemoji/1f50e.svg'
},
minCollision: 60,
neo4jData:neo4jData,
nodeRadius: 25,
onNodeDoubleClick: function(node) {
switch(node.id) {
case '25':
// Google
window.open(node.properties.url, '_blank');
break;
default:
var maxNodes = 5,
data = neo4jd3.randomD3Data(node, maxNodes);
neo4jd3.updateWithD3Data(data);
break;
}
},
onRelationshipDoubleClick: function(relationship) {
console.log('double click on relationship: ' + JSON.stringify(relationship));
},
zoomFit: true
});
}
render() {
return (
<div id={"id_"+this.uid} style={{height:500}}></div>
);
}
}
\ No newline at end of file
...@@ -52,6 +52,7 @@ import TableSelect from '../libs/TableSelect'; ...@@ -52,6 +52,7 @@ import TableSelect from '../libs/TableSelect';
import LocationCom from '../libs/LocationCom'; import LocationCom from '../libs/LocationCom';
import MobileDate from '../libs/MobileDate'; import MobileDate from '../libs/MobileDate';
import ChildForm from '../libs/ChildForm'; import ChildForm from '../libs/ChildForm';
import Neo4jD3Com from '../libs/Neo4jD3Com';
import ImgUploadCom from '../libs/ImgUploadCom'; import ImgUploadCom from '../libs/ImgUploadCom';
import moment from 'moment'; import moment from 'moment';
import router from 'umi/router'; import router from 'umi/router';
...@@ -814,7 +815,7 @@ export default class tableCom extends Component { ...@@ -814,7 +815,7 @@ export default class tableCom extends Component {
); );
//message.error(`页面${this.props.formKey}第${this.props.i + 1}行,第${this.props.j + 1}列:公式配置有误,回调函数内部错误${e}`, 10) //message.error(`页面${this.props.formKey}第${this.props.i + 1}行,第${this.props.j + 1}列:公式配置有误,回调函数内部错误${e}`, 10)
} }
} else if (json.comName == 'Echart' || json.comName == 'QRCode') { } else if (json.comName == 'Echart' || json.comName == 'QRCode'|| json.comName == 'Graph') {
try { try {
const x = callback(data); const x = callback(data);
if (x != null) { if (x != null) {
...@@ -888,7 +889,7 @@ export default class tableCom extends Component { ...@@ -888,7 +889,7 @@ export default class tableCom extends Component {
e, e,
); );
} }
} else if (json.comName == 'Echart' || json.comName == 'QRCode') { } else if (json.comName == 'Echart' || json.comName == 'QRCode'|| json.comName == 'Graph') {
try { try {
const x = callback(data); const x = callback(data);
if (x != null) { if (x != null) {
...@@ -964,7 +965,7 @@ export default class tableCom extends Component { ...@@ -964,7 +965,7 @@ export default class tableCom extends Component {
e, e,
); );
} }
} else if (json.comName == 'Echart' || json.comName == 'QRCode') { } else if (json.comName == 'Echart' || json.comName == 'QRCode'||json.comName == 'Graph') {
try { try {
const x = callback(data); const x = callback(data);
if (x != null) { if (x != null) {
...@@ -1044,7 +1045,7 @@ export default class tableCom extends Component { ...@@ -1044,7 +1045,7 @@ export default class tableCom extends Component {
e, e,
); );
} }
} else if (json.comName == 'Echart' || json.comName == 'QRCode') { } else if (json.comName == 'Echart' || json.comName == 'QRCode'||json.comName=="Graph") {
try { try {
const x = callback(data); const x = callback(data);
if (x != null) { if (x != null) {
...@@ -1177,7 +1178,7 @@ export default class tableCom extends Component { ...@@ -1177,7 +1178,7 @@ export default class tableCom extends Component {
if (callback) callback(); if (callback) callback();
}); });
} }
} else if (json.comName == 'Echart' || json.comName == 'QRCode') { } else if (json.comName == 'Echart' || json.comName == 'QRCode'||json.comName == 'Graph' ) {
this.setState({ option: value }); this.setState({ option: value });
} else { } else {
try { try {
...@@ -1464,6 +1465,16 @@ export default class tableCom extends Component { ...@@ -1464,6 +1465,16 @@ export default class tableCom extends Component {
/> />
); );
} }
if (json.comName == 'Graph') {
return (
<Neo4jD3Com
style={{ height: json.height || 500 }}
key={this.props.uuid}
option={this.state.option || []}/>
);
}
if (json.comName == 'PartForm') { if (json.comName == 'PartForm') {
const fk = this.props.form.getFieldValue(this.props.uuid) || json.childFormKey; const fk = this.props.form.getFieldValue(this.props.uuid) || json.childFormKey;
if (fk == null) { if (fk == null) {
......
'use strict';
import * as d3 from 'd3' ;
function Neo4jD3(_selector, _options) {
var container, graph, info, node, nodes, relationship, relationshipOutline, relationshipOverlay, relationshipText, relationships, selector, simulation, svg, svgNodes, svgRelationships, svgScale, svgTranslate,
classes2colors = {},
justLoaded = false,
numClasses = 0,
options = {
arrowSize: 4,
colors: colors(),
highlight: undefined,
iconMap: fontAwesomeIcons(),
icons: undefined,
imageMap: {},
images: undefined,
infoPanel: true,
minCollision: undefined,
neo4jData: undefined,
neo4jDataUrl: undefined,
nodeOutlineFillColor: undefined,
nodeRadius: 25,
relationshipColor: '#a5abb6',
zoomFit: false
},
VERSION = '0.0.1';
function appendGraph(container) {
svg = container.append('svg')
.attr('width', '100%')
.attr('height', '100%')
.attr('class', 'neo4jd3-graph')
.call(d3.zoom().on('zoom', function() {
var scale = d3.event.transform.k,
translate = [d3.event.transform.x, d3.event.transform.y];
if (svgTranslate) {
translate[0] += svgTranslate[0];
translate[1] += svgTranslate[1];
}
if (svgScale) {
scale *= svgScale;
}
svg.attr('transform', 'translate(' + translate[0] + ', ' + translate[1] + ') scale(' + scale + ')');
}))
.on('dblclick.zoom', null)
.append('g')
.attr('width', '100%')
.attr('height', '100%');
svgRelationships = svg.append('g')
.attr('class', 'relationships');
svgNodes = svg.append('g')
.attr('class', 'nodes');
}
function appendImageToNode(node) {
return node.append('image')
.attr('height', function(d) {
return icon(d) ? '24px': '30px';
})
.attr('x', function(d) {
return icon(d) ? '5px': '-15px';
})
.attr('xlink:href', function(d) {
return image(d);
})
.attr('y', function(d) {
return icon(d) ? '5px': '-16px';
})
.attr('width', function(d) {
return icon(d) ? '24px': '30px';
});
}
function appendInfoPanel(container) {
return container.append('div')
.attr('class', 'neo4jd3-info');
}
function appendInfoElement(cls, isNode, property, value) {
var elem = info.append('a');
elem.attr('href', '#')
.attr('class', cls)
.html('<strong>' + property + '</strong>' + (value ? (': ' + value) : ''));
if (!value) {
elem.style('background-color', function(d) {
return options.nodeOutlineFillColor ? options.nodeOutlineFillColor : (isNode ? class2color(property) : defaultColor());
})
.style('border-color', function(d) {
return options.nodeOutlineFillColor ? class2darkenColor(options.nodeOutlineFillColor) : (isNode ? class2darkenColor(property) : defaultDarkenColor());
})
.style('color', function(d) {
return options.nodeOutlineFillColor ? class2darkenColor(options.nodeOutlineFillColor) : '#fff';
});
}
}
function appendInfoElementClass(cls, node) {
appendInfoElement(cls, true, node);
}
function appendInfoElementProperty(cls, property, value) {
appendInfoElement(cls, false, property, value);
}
function appendInfoElementRelationship(cls, relationship) {
appendInfoElement(cls, false, relationship);
}
function appendNode() {
return node.enter()
.append('g')
.attr('class', function(d) {
var highlight, i,
classes = 'node',
label = d.labels[0];
if (icon(d)) {
classes += ' node-icon';
}
if (image(d)) {
classes += ' node-image';
}
if (options.highlight) {
for (i = 0; i < options.highlight.length; i++) {
highlight = options.highlight[i];
if (d.labels[0] === highlight.class && d.properties[highlight.property] === highlight.value) {
classes += ' node-highlighted';
break;
}
}
}
return classes;
})
.on('click', function(d) {
d.fx = d.fy = null;
if (typeof options.onNodeClick === 'function') {
options.onNodeClick(d);
}
})
.on('dblclick', function(d) {
stickNode(d);
if (typeof options.onNodeDoubleClick === 'function') {
options.onNodeDoubleClick(d);
}
})
.on('mouseenter', function(d) {
if (info) {
updateInfo(d);
}
if (typeof options.onNodeMouseEnter === 'function') {
options.onNodeMouseEnter(d);
}
})
.on('mouseleave', function(d) {
if (info) {
clearInfo(d);
}
if (typeof options.onNodeMouseLeave === 'function') {
options.onNodeMouseLeave(d);
}
})
.call(d3.drag()
.on('start', dragStarted)
.on('drag', dragged)
.on('end', dragEnded));
}
function appendNodeToGraph() {
var n = appendNode();
appendRingToNode(n);
appendOutlineToNode(n);
if (options.icons) {
appendTextToNode(n);
}
if (options.images) {
appendImageToNode(n);
}
return n;
}
function appendOutlineToNode(node) {
return node.append('circle')
.attr('class', 'outline')
.attr('r', options.nodeRadius)
.style('fill', function(d) {
return options.nodeOutlineFillColor ? options.nodeOutlineFillColor : class2color(d.labels[0]);
})
.style('stroke', function(d) {
return options.nodeOutlineFillColor ? class2darkenColor(options.nodeOutlineFillColor) : class2darkenColor(d.labels[0]);
})
.append('title').text(function(d) {
return toString(d);
});
}
function appendRingToNode(node) {
return node.append('circle')
.attr('class', 'ring')
.attr('r', options.nodeRadius * 1.16)
.append('title').text(function(d) {
return toString(d);
});
}
function appendTextToNode(node) {
return node.append('text')
.attr('class', function(d) {
return 'text' + (icon(d) ? ' icon' : '');
})
.attr('fill', '#ffffff')
.attr('font-size', function(d) {
return icon(d) ? (options.nodeRadius + 'px') : '10px';
})
.attr('pointer-events', 'none')
.attr('text-anchor', 'middle')
.attr('y', function(d) {
return icon(d) ? (parseInt(Math.round(options.nodeRadius * 0.32)) + 'px') : '4px';
})
.html(function(d) {
var _icon = icon(d);
return _icon ? '&#x' + _icon : d.id;
});
}
function appendRandomDataToNode(d, maxNodesToGenerate) {
var data = randomD3Data(d, maxNodesToGenerate);
updateWithNeo4jData(data);
}
function appendRelationship() {
return relationship.enter()
.append('g')
.attr('class', 'relationship')
.on('dblclick', function(d) {
if (typeof options.onRelationshipDoubleClick === 'function') {
options.onRelationshipDoubleClick(d);
}
})
.on('mouseenter', function(d) {
if (info) {
updateInfo(d);
}
});
}
function appendOutlineToRelationship(r) {
return r.append('path')
.attr('class', 'outline')
.attr('fill', '#a5abb6')
.attr('stroke', 'none');
}
function appendOverlayToRelationship(r) {
return r.append('path')
.attr('class', 'overlay');
}
function appendTextToRelationship(r) {
return r.append('text')
.attr('class', 'text')
.attr('fill', '#000000')
.attr('font-size', '8px')
.attr('pointer-events', 'none')
.attr('text-anchor', 'middle')
.text(function(d) {
return d.type;
});
}
function appendRelationshipToGraph() {
var relationship = appendRelationship(),
text = appendTextToRelationship(relationship),
outline = appendOutlineToRelationship(relationship),
overlay = appendOverlayToRelationship(relationship);
return {
outline: outline,
overlay: overlay,
relationship: relationship,
text: text
};
}
function class2color(cls) {
var color = classes2colors[cls];
if (!color) {
// color = options.colors[Math.min(numClasses, options.colors.length - 1)];
color = options.colors[numClasses % options.colors.length];
classes2colors[cls] = color;
numClasses++;
}
return color;
}
function class2darkenColor(cls) {
return d3.rgb(class2color(cls)).darker(1);
}
function clearInfo() {
info.html('');
}
function color() {
return options.colors[options.colors.length * Math.random() << 0];
}
function colors() {
// d3.schemeCategory10,
// d3.schemeCategory20,
return [
'#68bdf6', // light blue
'#6dce9e', // green #1
'#faafc2', // light pink
'#f2baf6', // purple
'#ff928c', // light red
'#fcea7e', // light yellow
'#ffc766', // light orange
'#405f9e', // navy blue
'#a5abb6', // dark gray
'#78cecb', // green #2,
'#b88cbb', // dark purple
'#ced2d9', // light gray
'#e84646', // dark red
'#fa5f86', // dark pink
'#ffab1a', // dark orange
'#fcda19', // dark yellow
'#797b80', // black
'#c9d96f', // pistacchio
'#47991f', // green #3
'#70edee', // turquoise
'#ff75ea' // pink
];
}
function contains(array, id) {
var filter = array.filter(function(elem) {
return elem.id === id;
});
return filter.length > 0;
}
function defaultColor() {
return options.relationshipColor;
}
function defaultDarkenColor() {
return d3.rgb(options.colors[options.colors.length - 1]).darker(1);
}
function dragEnded(d) {
if (!d3.event.active) {
simulation.alphaTarget(0);
}
if (typeof options.onNodeDragEnd === 'function') {
options.onNodeDragEnd(d);
}
}
function dragged(d) {
stickNode(d);
}
function dragStarted(d) {
if (!d3.event.active) {
simulation.alphaTarget(0.3).restart();
}
d.fx = d.x;
d.fy = d.y;
if (typeof options.onNodeDragStart === 'function') {
options.onNodeDragStart(d);
}
}
function extend(obj1, obj2) {
var obj = {};
merge(obj, obj1);
merge(obj, obj2);
return obj;
}
function fontAwesomeIcons() {
return {'glass':'f000','music':'f001','search':'f002','envelope-o':'f003','heart':'f004','star':'f005','star-o':'f006','user':'f007','film':'f008','th-large':'f009','th':'f00a','th-list':'f00b','check':'f00c','remove,close,times':'f00d','search-plus':'f00e','search-minus':'f010','power-off':'f011','signal':'f012','gear,cog':'f013','trash-o':'f014','home':'f015','file-o':'f016','clock-o':'f017','road':'f018','download':'f019','arrow-circle-o-down':'f01a','arrow-circle-o-up':'f01b','inbox':'f01c','play-circle-o':'f01d','rotate-right,repeat':'f01e','refresh':'f021','list-alt':'f022','lock':'f023','flag':'f024','headphones':'f025','volume-off':'f026','volume-down':'f027','volume-up':'f028','qrcode':'f029','barcode':'f02a','tag':'f02b','tags':'f02c','book':'f02d','bookmark':'f02e','print':'f02f','camera':'f030','font':'f031','bold':'f032','italic':'f033','text-height':'f034','text-width':'f035','align-left':'f036','align-center':'f037','align-right':'f038','align-justify':'f039','list':'f03a','dedent,outdent':'f03b','indent':'f03c','video-camera':'f03d','photo,image,picture-o':'f03e','pencil':'f040','map-marker':'f041','adjust':'f042','tint':'f043','edit,pencil-square-o':'f044','share-square-o':'f045','check-square-o':'f046','arrows':'f047','step-backward':'f048','fast-backward':'f049','backward':'f04a','play':'f04b','pause':'f04c','stop':'f04d','forward':'f04e','fast-forward':'f050','step-forward':'f051','eject':'f052','chevron-left':'f053','chevron-right':'f054','plus-circle':'f055','minus-circle':'f056','times-circle':'f057','check-circle':'f058','question-circle':'f059','info-circle':'f05a','crosshairs':'f05b','times-circle-o':'f05c','check-circle-o':'f05d','ban':'f05e','arrow-left':'f060','arrow-right':'f061','arrow-up':'f062','arrow-down':'f063','mail-forward,share':'f064','expand':'f065','compress':'f066','plus':'f067','minus':'f068','asterisk':'f069','exclamation-circle':'f06a','gift':'f06b','leaf':'f06c','fire':'f06d','eye':'f06e','eye-slash':'f070','warning,exclamation-triangle':'f071','plane':'f072','calendar':'f073','random':'f074','comment':'f075','magnet':'f076','chevron-up':'f077','chevron-down':'f078','retweet':'f079','shopping-cart':'f07a','folder':'f07b','folder-open':'f07c','arrows-v':'f07d','arrows-h':'f07e','bar-chart-o,bar-chart':'f080','twitter-square':'f081','facebook-square':'f082','camera-retro':'f083','key':'f084','gears,cogs':'f085','comments':'f086','thumbs-o-up':'f087','thumbs-o-down':'f088','star-half':'f089','heart-o':'f08a','sign-out':'f08b','linkedin-square':'f08c','thumb-tack':'f08d','external-link':'f08e','sign-in':'f090','trophy':'f091','github-square':'f092','upload':'f093','lemon-o':'f094','phone':'f095','square-o':'f096','bookmark-o':'f097','phone-square':'f098','twitter':'f099','facebook-f,facebook':'f09a','github':'f09b','unlock':'f09c','credit-card':'f09d','feed,rss':'f09e','hdd-o':'f0a0','bullhorn':'f0a1','bell':'f0f3','certificate':'f0a3','hand-o-right':'f0a4','hand-o-left':'f0a5','hand-o-up':'f0a6','hand-o-down':'f0a7','arrow-circle-left':'f0a8','arrow-circle-right':'f0a9','arrow-circle-up':'f0aa','arrow-circle-down':'f0ab','globe':'f0ac','wrench':'f0ad','tasks':'f0ae','filter':'f0b0','briefcase':'f0b1','arrows-alt':'f0b2','group,users':'f0c0','chain,link':'f0c1','cloud':'f0c2','flask':'f0c3','cut,scissors':'f0c4','copy,files-o':'f0c5','paperclip':'f0c6','save,floppy-o':'f0c7','square':'f0c8','navicon,reorder,bars':'f0c9','list-ul':'f0ca','list-ol':'f0cb','strikethrough':'f0cc','underline':'f0cd','table':'f0ce','magic':'f0d0','truck':'f0d1','pinterest':'f0d2','pinterest-square':'f0d3','google-plus-square':'f0d4','google-plus':'f0d5','money':'f0d6','caret-down':'f0d7','caret-up':'f0d8','caret-left':'f0d9','caret-right':'f0da','columns':'f0db','unsorted,sort':'f0dc','sort-down,sort-desc':'f0dd','sort-up,sort-asc':'f0de','envelope':'f0e0','linkedin':'f0e1','rotate-left,undo':'f0e2','legal,gavel':'f0e3','dashboard,tachometer':'f0e4','comment-o':'f0e5','comments-o':'f0e6','flash,bolt':'f0e7','sitemap':'f0e8','umbrella':'f0e9','paste,clipboard':'f0ea','lightbulb-o':'f0eb','exchange':'f0ec','cloud-download':'f0ed','cloud-upload':'f0ee','user-md':'f0f0','stethoscope':'f0f1','suitcase':'f0f2','bell-o':'f0a2','coffee':'f0f4','cutlery':'f0f5','file-text-o':'f0f6','building-o':'f0f7','hospital-o':'f0f8','ambulance':'f0f9','medkit':'f0fa','fighter-jet':'f0fb','beer':'f0fc','h-square':'f0fd','plus-square':'f0fe','angle-double-left':'f100','angle-double-right':'f101','angle-double-up':'f102','angle-double-down':'f103','angle-left':'f104','angle-right':'f105','angle-up':'f106','angle-down':'f107','desktop':'f108','laptop':'f109','tablet':'f10a','mobile-phone,mobile':'f10b','circle-o':'f10c','quote-left':'f10d','quote-right':'f10e','spinner':'f110','circle':'f111','mail-reply,reply':'f112','github-alt':'f113','folder-o':'f114','folder-open-o':'f115','smile-o':'f118','frown-o':'f119','meh-o':'f11a','gamepad':'f11b','keyboard-o':'f11c','flag-o':'f11d','flag-checkered':'f11e','terminal':'f120','code':'f121','mail-reply-all,reply-all':'f122','star-half-empty,star-half-full,star-half-o':'f123','location-arrow':'f124','crop':'f125','code-fork':'f126','unlink,chain-broken':'f127','question':'f128','info':'f129','exclamation':'f12a','superscript':'f12b','subscript':'f12c','eraser':'f12d','puzzle-piece':'f12e','microphone':'f130','microphone-slash':'f131','shield':'f132','calendar-o':'f133','fire-extinguisher':'f134','rocket':'f135','maxcdn':'f136','chevron-circle-left':'f137','chevron-circle-right':'f138','chevron-circle-up':'f139','chevron-circle-down':'f13a','html5':'f13b','css3':'f13c','anchor':'f13d','unlock-alt':'f13e','bullseye':'f140','ellipsis-h':'f141','ellipsis-v':'f142','rss-square':'f143','play-circle':'f144','ticket':'f145','minus-square':'f146','minus-square-o':'f147','level-up':'f148','level-down':'f149','check-square':'f14a','pencil-square':'f14b','external-link-square':'f14c','share-square':'f14d','compass':'f14e','toggle-down,caret-square-o-down':'f150','toggle-up,caret-square-o-up':'f151','toggle-right,caret-square-o-right':'f152','euro,eur':'f153','gbp':'f154','dollar,usd':'f155','rupee,inr':'f156','cny,rmb,yen,jpy':'f157','ruble,rouble,rub':'f158','won,krw':'f159','bitcoin,btc':'f15a','file':'f15b','file-text':'f15c','sort-alpha-asc':'f15d','sort-alpha-desc':'f15e','sort-amount-asc':'f160','sort-amount-desc':'f161','sort-numeric-asc':'f162','sort-numeric-desc':'f163','thumbs-up':'f164','thumbs-down':'f165','youtube-square':'f166','youtube':'f167','xing':'f168','xing-square':'f169','youtube-play':'f16a','dropbox':'f16b','stack-overflow':'f16c','instagram':'f16d','flickr':'f16e','adn':'f170','bitbucket':'f171','bitbucket-square':'f172','tumblr':'f173','tumblr-square':'f174','long-arrow-down':'f175','long-arrow-up':'f176','long-arrow-left':'f177','long-arrow-right':'f178','apple':'f179','windows':'f17a','android':'f17b','linux':'f17c','dribbble':'f17d','skype':'f17e','foursquare':'f180','trello':'f181','female':'f182','male':'f183','gittip,gratipay':'f184','sun-o':'f185','moon-o':'f186','archive':'f187','bug':'f188','vk':'f189','weibo':'f18a','renren':'f18b','pagelines':'f18c','stack-exchange':'f18d','arrow-circle-o-right':'f18e','arrow-circle-o-left':'f190','toggle-left,caret-square-o-left':'f191','dot-circle-o':'f192','wheelchair':'f193','vimeo-square':'f194','turkish-lira,try':'f195','plus-square-o':'f196','space-shuttle':'f197','slack':'f198','envelope-square':'f199','wordpress':'f19a','openid':'f19b','institution,bank,university':'f19c','mortar-board,graduation-cap':'f19d','yahoo':'f19e','google':'f1a0','reddit':'f1a1','reddit-square':'f1a2','stumbleupon-circle':'f1a3','stumbleupon':'f1a4','delicious':'f1a5','digg':'f1a6','pied-piper-pp':'f1a7','pied-piper-alt':'f1a8','drupal':'f1a9','joomla':'f1aa','language':'f1ab','fax':'f1ac','building':'f1ad','child':'f1ae','paw':'f1b0','spoon':'f1b1','cube':'f1b2','cubes':'f1b3','behance':'f1b4','behance-square':'f1b5','steam':'f1b6','steam-square':'f1b7','recycle':'f1b8','automobile,car':'f1b9','cab,taxi':'f1ba','tree':'f1bb','spotify':'f1bc','deviantart':'f1bd','soundcloud':'f1be','database':'f1c0','file-pdf-o':'f1c1','file-word-o':'f1c2','file-excel-o':'f1c3','file-powerpoint-o':'f1c4','file-photo-o,file-picture-o,file-image-o':'f1c5','file-zip-o,file-archive-o':'f1c6','file-sound-o,file-audio-o':'f1c7','file-movie-o,file-video-o':'f1c8','file-code-o':'f1c9','vine':'f1ca','codepen':'f1cb','jsfiddle':'f1cc','life-bouy,life-buoy,life-saver,support,life-ring':'f1cd','circle-o-notch':'f1ce','ra,resistance,rebel':'f1d0','ge,empire':'f1d1','git-square':'f1d2','git':'f1d3','y-combinator-square,yc-square,hacker-news':'f1d4','tencent-weibo':'f1d5','qq':'f1d6','wechat,weixin':'f1d7','send,paper-plane':'f1d8','send-o,paper-plane-o':'f1d9','history':'f1da','circle-thin':'f1db','header':'f1dc','paragraph':'f1dd','sliders':'f1de','share-alt':'f1e0','share-alt-square':'f1e1','bomb':'f1e2','soccer-ball-o,futbol-o':'f1e3','tty':'f1e4','binoculars':'f1e5','plug':'f1e6','slideshare':'f1e7','twitch':'f1e8','yelp':'f1e9','newspaper-o':'f1ea','wifi':'f1eb','calculator':'f1ec','paypal':'f1ed','google-wallet':'f1ee','cc-visa':'f1f0','cc-mastercard':'f1f1','cc-discover':'f1f2','cc-amex':'f1f3','cc-paypal':'f1f4','cc-stripe':'f1f5','bell-slash':'f1f6','bell-slash-o':'f1f7','trash':'f1f8','copyright':'f1f9','at':'f1fa','eyedropper':'f1fb','paint-brush':'f1fc','birthday-cake':'f1fd','area-chart':'f1fe','pie-chart':'f200','line-chart':'f201','lastfm':'f202','lastfm-square':'f203','toggle-off':'f204','toggle-on':'f205','bicycle':'f206','bus':'f207','ioxhost':'f208','angellist':'f209','cc':'f20a','shekel,sheqel,ils':'f20b','meanpath':'f20c','buysellads':'f20d','connectdevelop':'f20e','dashcube':'f210','forumbee':'f211','leanpub':'f212','sellsy':'f213','shirtsinbulk':'f214','simplybuilt':'f215','skyatlas':'f216','cart-plus':'f217','cart-arrow-down':'f218','diamond':'f219','ship':'f21a','user-secret':'f21b','motorcycle':'f21c','street-view':'f21d','heartbeat':'f21e','venus':'f221','mars':'f222','mercury':'f223','intersex,transgender':'f224','transgender-alt':'f225','venus-double':'f226','mars-double':'f227','venus-mars':'f228','mars-stroke':'f229','mars-stroke-v':'f22a','mars-stroke-h':'f22b','neuter':'f22c','genderless':'f22d','facebook-official':'f230','pinterest-p':'f231','whatsapp':'f232','server':'f233','user-plus':'f234','user-times':'f235','hotel,bed':'f236','viacoin':'f237','train':'f238','subway':'f239','medium':'f23a','yc,y-combinator':'f23b','optin-monster':'f23c','opencart':'f23d','expeditedssl':'f23e','battery-4,battery-full':'f240','battery-3,battery-three-quarters':'f241','battery-2,battery-half':'f242','battery-1,battery-quarter':'f243','battery-0,battery-empty':'f244','mouse-pointer':'f245','i-cursor':'f246','object-group':'f247','object-ungroup':'f248','sticky-note':'f249','sticky-note-o':'f24a','cc-jcb':'f24b','cc-diners-club':'f24c','clone':'f24d','balance-scale':'f24e','hourglass-o':'f250','hourglass-1,hourglass-start':'f251','hourglass-2,hourglass-half':'f252','hourglass-3,hourglass-end':'f253','hourglass':'f254','hand-grab-o,hand-rock-o':'f255','hand-stop-o,hand-paper-o':'f256','hand-scissors-o':'f257','hand-lizard-o':'f258','hand-spock-o':'f259','hand-pointer-o':'f25a','hand-peace-o':'f25b','trademark':'f25c','registered':'f25d','creative-commons':'f25e','gg':'f260','gg-circle':'f261','tripadvisor':'f262','odnoklassniki':'f263','odnoklassniki-square':'f264','get-pocket':'f265','wikipedia-w':'f266','safari':'f267','chrome':'f268','firefox':'f269','opera':'f26a','internet-explorer':'f26b','tv,television':'f26c','contao':'f26d','500px':'f26e','amazon':'f270','calendar-plus-o':'f271','calendar-minus-o':'f272','calendar-times-o':'f273','calendar-check-o':'f274','industry':'f275','map-pin':'f276','map-signs':'f277','map-o':'f278','map':'f279','commenting':'f27a','commenting-o':'f27b','houzz':'f27c','vimeo':'f27d','black-tie':'f27e','fonticons':'f280','reddit-alien':'f281','edge':'f282','credit-card-alt':'f283','codiepie':'f284','modx':'f285','fort-awesome':'f286','usb':'f287','product-hunt':'f288','mixcloud':'f289','scribd':'f28a','pause-circle':'f28b','pause-circle-o':'f28c','stop-circle':'f28d','stop-circle-o':'f28e','shopping-bag':'f290','shopping-basket':'f291','hashtag':'f292','bluetooth':'f293','bluetooth-b':'f294','percent':'f295','gitlab':'f296','wpbeginner':'f297','wpforms':'f298','envira':'f299','universal-access':'f29a','wheelchair-alt':'f29b','question-circle-o':'f29c','blind':'f29d','audio-description':'f29e','volume-control-phone':'f2a0','braille':'f2a1','assistive-listening-systems':'f2a2','asl-interpreting,american-sign-language-interpreting':'f2a3','deafness,hard-of-hearing,deaf':'f2a4','glide':'f2a5','glide-g':'f2a6','signing,sign-language':'f2a7','low-vision':'f2a8','viadeo':'f2a9','viadeo-square':'f2aa','snapchat':'f2ab','snapchat-ghost':'f2ac','snapchat-square':'f2ad','pied-piper':'f2ae','first-order':'f2b0','yoast':'f2b1','themeisle':'f2b2','google-plus-circle,google-plus-official':'f2b3','fa,font-awesome':'f2b4'};
}
function icon(d) {
var code;
if (options.iconMap && options.showIcons && options.icons) {
if (options.icons[d.labels[0]] && options.iconMap[options.icons[d.labels[0]]]) {
code = options.iconMap[options.icons[d.labels[0]]];
} else if (options.iconMap[d.labels[0]]) {
code = options.iconMap[d.labels[0]];
} else if (options.icons[d.labels[0]]) {
code = options.icons[d.labels[0]];
}
}
return code;
}
function image(d) {
var i, imagesForLabel, img, imgLevel, label, labelPropertyValue, property, value;
if (options.images) {
imagesForLabel = options.imageMap[d.labels[0]];
if (imagesForLabel) {
imgLevel = 0;
for (i = 0; i < imagesForLabel.length; i++) {
labelPropertyValue = imagesForLabel[i].split('|');
switch (labelPropertyValue.length) {
case 3:
value = labelPropertyValue[2];
/* falls through */
case 2:
property = labelPropertyValue[1];
/* falls through */
case 1:
label = labelPropertyValue[0];
}
if (d.labels[0] === label &&
(!property || d.properties[property] !== undefined) &&
(!value || d.properties[property] === value)) {
if (labelPropertyValue.length > imgLevel) {
img = options.images[imagesForLabel[i]];
imgLevel = labelPropertyValue.length;
}
}
}
}
}
return img;
}
function init(_selector, _options) {
initIconMap();
merge(options, _options);
if (options.icons) {
options.showIcons = true;
}
if (!options.minCollision) {
options.minCollision = options.nodeRadius * 2;
}
initImageMap();
selector = _selector;
container = d3.select(selector);
container.attr('class', 'neo4jd3')
.html('');
if (options.infoPanel) {
info = appendInfoPanel(container);
}
appendGraph(container);
simulation = initSimulation();
if (options.neo4jData) {
loadNeo4jData(options.neo4jData);
} else if (options.neo4jDataUrl) {
loadNeo4jDataFromUrl(options.neo4jDataUrl);
} else {
console.error('Error: both neo4jData and neo4jDataUrl are empty!');
}
}
function initIconMap() {
Object.keys(options.iconMap).forEach(function(key, index) {
var keys = key.split(','),
value = options.iconMap[key];
keys.forEach(function(key) {
options.iconMap[key] = value;
});
});
}
function initImageMap() {
var key, keys, selector;
for (key in options.images) {
if (options.images.hasOwnProperty(key)) {
keys = key.split('|');
if (!options.imageMap[keys[0]]) {
options.imageMap[keys[0]] = [key];
} else {
options.imageMap[keys[0]].push(key);
}
}
}
}
function initSimulation() {
var simulation = d3.forceSimulation()
// .velocityDecay(0.8)
// .force('x', d3.force().strength(0.002))
// .force('y', d3.force().strength(0.002))
.force('collide', d3.forceCollide().radius(function(d) {
return options.minCollision;
}).iterations(2))
.force('charge', d3.forceManyBody())
.force('link', d3.forceLink().id(function(d) {
return d.id;
}))
.force('center', d3.forceCenter(svg.node().parentElement.parentElement.clientWidth / 2, svg.node().parentElement.parentElement.clientHeight / 2))
.on('tick', function() {
tick();
})
.on('end', function() {
if (options.zoomFit && !justLoaded) {
justLoaded = true;
zoomFit(2);
}
});
return simulation;
}
function loadNeo4jData() {
nodes = [];
relationships = [];
updateWithNeo4jData(options.neo4jData);
}
function loadNeo4jDataFromUrl(neo4jDataUrl) {
nodes = [];
relationships = [];
d3.json(neo4jDataUrl, function(error, data) {
if (error) {
throw error;
}
updateWithNeo4jData(data);
});
}
function merge(target, source) {
Object.keys(source).forEach(function(property) {
target[property] = source[property];
});
}
function neo4jDataToD3Data(data) {
return data;
var graph = {
nodes: [],
relationships: []
};
data.results.forEach(function(result) {
result.data.forEach(function(data) {
data.graph.nodes.forEach(function(node) {
if (!contains(graph.nodes, node.id)) {
graph.nodes.push(node);
}
});
data.graph.relationships.forEach(function(relationship) {
relationship.source = relationship.startNode;
relationship.target = relationship.endNode;
graph.relationships.push(relationship);
});
data.graph.relationships.sort(function(a, b) {
if (a.source > b.source) {
return 1;
} else if (a.source < b.source) {
return -1;
} else {
if (a.target > b.target) {
return 1;
}
if (a.target < b.target) {
return -1;
} else {
return 0;
}
}
});
for (var i = 0; i < data.graph.relationships.length; i++) {
if (i !== 0 && data.graph.relationships[i].source === data.graph.relationships[i-1].source && data.graph.relationships[i].target === data.graph.relationships[i-1].target) {
data.graph.relationships[i].linknum = data.graph.relationships[i - 1].linknum + 1;
} else {
data.graph.relationships[i].linknum = 1;
}
}
});
});
return graph;
}
function randomD3Data(d, maxNodesToGenerate) {
var data = {
nodes: [],
relationships: []
},
i,
label,
node,
numNodes = (maxNodesToGenerate * Math.random() << 0) + 1,
relationship,
s = size();
for (i = 0; i < numNodes; i++) {
label = randomLabel();
node = {
id: s.nodes + 1 + i,
labels: [label],
properties: {
random: label
},
x: d.x,
y: d.y
};
data.nodes[data.nodes.length] = node;
relationship = {
id: s.relationships + 1 + i,
type: label.toUpperCase(),
startNode: d.id,
endNode: s.nodes + 1 + i,
properties: {
from: Date.now()
},
source: d.id,
target: s.nodes + 1 + i,
linknum: s.relationships + 1 + i
};
data.relationships[data.relationships.length] = relationship;
}
return data;
}
function randomLabel() {
var icons = Object.keys(options.iconMap);
return icons[icons.length * Math.random() << 0];
}
function rotate(cx, cy, x, y, angle) {
var radians = (Math.PI / 180) * angle,
cos = Math.cos(radians),
sin = Math.sin(radians),
nx = (cos * (x - cx)) + (sin * (y - cy)) + cx,
ny = (cos * (y - cy)) - (sin * (x - cx)) + cy;
return { x: nx, y: ny };
}
function rotatePoint(c, p, angle) {
return rotate(c.x, c.y, p.x, p.y, angle);
}
function rotation(source, target) {
return Math.atan2(target.y - source.y, target.x - source.x) * 180 / Math.PI;
}
function size() {
return {
nodes: nodes.length,
relationships: relationships.length
};
}
/*
function smoothTransform(elem, translate, scale) {
var animationMilliseconds = 5000,
timeoutMilliseconds = 50,
steps = parseInt(animationMilliseconds / timeoutMilliseconds);
setTimeout(function() {
smoothTransformStep(elem, translate, scale, timeoutMilliseconds, 1, steps);
}, timeoutMilliseconds);
}
function smoothTransformStep(elem, translate, scale, timeoutMilliseconds, step, steps) {
var progress = step / steps;
elem.attr('transform', 'translate(' + (translate[0] * progress) + ', ' + (translate[1] * progress) + ') scale(' + (scale * progress) + ')');
if (step < steps) {
setTimeout(function() {
smoothTransformStep(elem, translate, scale, timeoutMilliseconds, step + 1, steps);
}, timeoutMilliseconds);
}
}
*/
function stickNode(d) {
d.fx = d3.event.x;
d.fy = d3.event.y;
}
function tick() {
tickNodes();
tickRelationships();
}
function tickNodes() {
if (node) {
node.attr('transform', function(d) {
return 'translate(' + d.x + ', ' + d.y + ')';
});
}
}
function tickRelationships() {
if (relationship) {
relationship.attr('transform', function(d) {
var angle = rotation(d.source, d.target);
return 'translate(' + d.source.x + ', ' + d.source.y + ') rotate(' + angle + ')';
});
tickRelationshipsTexts();
tickRelationshipsOutlines();
tickRelationshipsOverlays();
}
}
function tickRelationshipsOutlines() {
relationship.each(function(relationship) {
var rel = d3.select(this),
outline = rel.select('.outline'),
text = rel.select('.text'),
bbox = text.node().getBBox(),
padding = 3;
outline.attr('d', function(d) {
var center = { x: 0, y: 0 },
angle = rotation(d.source, d.target),
textBoundingBox = text.node().getBBox(),
textPadding = 5,
u = unitaryVector(d.source, d.target),
textMargin = { x: (d.target.x - d.source.x - (textBoundingBox.width + textPadding) * u.x) * 0.5, y: (d.target.y - d.source.y - (textBoundingBox.width + textPadding) * u.y) * 0.5 },
n = unitaryNormalVector(d.source, d.target),
rotatedPointA1 = rotatePoint(center, { x: 0 + (options.nodeRadius + 1) * u.x - n.x, y: 0 + (options.nodeRadius + 1) * u.y - n.y }, angle),
rotatedPointB1 = rotatePoint(center, { x: textMargin.x - n.x, y: textMargin.y - n.y }, angle),
rotatedPointC1 = rotatePoint(center, { x: textMargin.x, y: textMargin.y }, angle),
rotatedPointD1 = rotatePoint(center, { x: 0 + (options.nodeRadius + 1) * u.x, y: 0 + (options.nodeRadius + 1) * u.y }, angle),
rotatedPointA2 = rotatePoint(center, { x: d.target.x - d.source.x - textMargin.x - n.x, y: d.target.y - d.source.y - textMargin.y - n.y }, angle),
rotatedPointB2 = rotatePoint(center, { x: d.target.x - d.source.x - (options.nodeRadius + 1) * u.x - n.x - u.x * options.arrowSize, y: d.target.y - d.source.y - (options.nodeRadius + 1) * u.y - n.y - u.y * options.arrowSize }, angle),
rotatedPointC2 = rotatePoint(center, { x: d.target.x - d.source.x - (options.nodeRadius + 1) * u.x - n.x + (n.x - u.x) * options.arrowSize, y: d.target.y - d.source.y - (options.nodeRadius + 1) * u.y - n.y + (n.y - u.y) * options.arrowSize }, angle),
rotatedPointD2 = rotatePoint(center, { x: d.target.x - d.source.x - (options.nodeRadius + 1) * u.x, y: d.target.y - d.source.y - (options.nodeRadius + 1) * u.y }, angle),
rotatedPointE2 = rotatePoint(center, { x: d.target.x - d.source.x - (options.nodeRadius + 1) * u.x + (- n.x - u.x) * options.arrowSize, y: d.target.y - d.source.y - (options.nodeRadius + 1) * u.y + (- n.y - u.y) * options.arrowSize }, angle),
rotatedPointF2 = rotatePoint(center, { x: d.target.x - d.source.x - (options.nodeRadius + 1) * u.x - u.x * options.arrowSize, y: d.target.y - d.source.y - (options.nodeRadius + 1) * u.y - u.y * options.arrowSize }, angle),
rotatedPointG2 = rotatePoint(center, { x: d.target.x - d.source.x - textMargin.x, y: d.target.y - d.source.y - textMargin.y }, angle);
return 'M ' + rotatedPointA1.x + ' ' + rotatedPointA1.y +
' L ' + rotatedPointB1.x + ' ' + rotatedPointB1.y +
' L ' + rotatedPointC1.x + ' ' + rotatedPointC1.y +
' L ' + rotatedPointD1.x + ' ' + rotatedPointD1.y +
' Z M ' + rotatedPointA2.x + ' ' + rotatedPointA2.y +
' L ' + rotatedPointB2.x + ' ' + rotatedPointB2.y +
' L ' + rotatedPointC2.x + ' ' + rotatedPointC2.y +
' L ' + rotatedPointD2.x + ' ' + rotatedPointD2.y +
' L ' + rotatedPointE2.x + ' ' + rotatedPointE2.y +
' L ' + rotatedPointF2.x + ' ' + rotatedPointF2.y +
' L ' + rotatedPointG2.x + ' ' + rotatedPointG2.y +
' Z';
});
});
}
function tickRelationshipsOverlays() {
relationshipOverlay.attr('d', function(d) {
var center = { x: 0, y: 0 },
angle = rotation(d.source, d.target),
n1 = unitaryNormalVector(d.source, d.target),
n = unitaryNormalVector(d.source, d.target, 50),
rotatedPointA = rotatePoint(center, { x: 0 - n.x, y: 0 - n.y }, angle),
rotatedPointB = rotatePoint(center, { x: d.target.x - d.source.x - n.x, y: d.target.y - d.source.y - n.y }, angle),
rotatedPointC = rotatePoint(center, { x: d.target.x - d.source.x + n.x - n1.x, y: d.target.y - d.source.y + n.y - n1.y }, angle),
rotatedPointD = rotatePoint(center, { x: 0 + n.x - n1.x, y: 0 + n.y - n1.y }, angle);
return 'M ' + rotatedPointA.x + ' ' + rotatedPointA.y +
' L ' + rotatedPointB.x + ' ' + rotatedPointB.y +
' L ' + rotatedPointC.x + ' ' + rotatedPointC.y +
' L ' + rotatedPointD.x + ' ' + rotatedPointD.y +
' Z';
});
}
function tickRelationshipsTexts() {
relationshipText.attr('transform', function(d) {
var angle = (rotation(d.source, d.target) + 360) % 360,
mirror = angle > 90 && angle < 270,
center = { x: 0, y: 0 },
n = unitaryNormalVector(d.source, d.target),
nWeight = mirror ? 2 : -3,
point = { x: (d.target.x - d.source.x) * 0.5 + n.x * nWeight, y: (d.target.y - d.source.y) * 0.5 + n.y * nWeight },
rotatedPoint = rotatePoint(center, point, angle);
return 'translate(' + rotatedPoint.x + ', ' + rotatedPoint.y + ') rotate(' + (mirror ? 180 : 0) + ')';
});
}
function toString(d) {
var s = d.labels ? d.labels[0] : d.type;
s += ' (<id>: ' + d.id;
Object.keys(d.properties).forEach(function(property) {
s += ', ' + property + ': ' + JSON.stringify(d.properties[property]);
});
s += ')';
return s;
}
function unitaryNormalVector(source, target, newLength) {
var center = { x: 0, y: 0 },
vector = unitaryVector(source, target, newLength);
return rotatePoint(center, vector, 90);
}
function unitaryVector(source, target, newLength) {
var length = Math.sqrt(Math.pow(target.x - source.x, 2) + Math.pow(target.y - source.y, 2)) / Math.sqrt(newLength || 1);
return {
x: (target.x - source.x) / length,
y: (target.y - source.y) / length,
};
}
function updateWithD3Data(d3Data) {
updateNodesAndRelationships(d3Data.nodes, d3Data.relationships);
}
function updateWithNeo4jData(neo4jData) {
var d3Data = neo4jDataToD3Data(neo4jData);
updateWithD3Data(d3Data);
}
function updateInfo(d) {
clearInfo();
if (d.labels) {
appendInfoElementClass('class', d.labels[0]);
} else {
appendInfoElementRelationship('class', d.type);
}
appendInfoElementProperty('property', '&lt;id&gt;', d.id);
Object.keys(d.properties).forEach(function(property) {
appendInfoElementProperty('property', property, JSON.stringify(d.properties[property]));
});
}
function updateNodes(n) {
Array.prototype.push.apply(nodes, n);
node = svgNodes.selectAll('.node')
.data(nodes, function(d) { return d.id; });
var nodeEnter = appendNodeToGraph();
node = nodeEnter.merge(node);
}
function updateNodesAndRelationships(n, r) {
updateRelationships(r);
updateNodes(n);
simulation.nodes(nodes);
simulation.force('link').links(relationships);
}
function updateRelationships(r) {
Array.prototype.push.apply(relationships, r);
relationship = svgRelationships.selectAll('.relationship')
.data(relationships, function(d) { return d.id; });
var relationshipEnter = appendRelationshipToGraph();
relationship = relationshipEnter.relationship.merge(relationship);
relationshipOutline = svg.selectAll('.relationship .outline');
relationshipOutline = relationshipEnter.outline.merge(relationshipOutline);
relationshipOverlay = svg.selectAll('.relationship .overlay');
relationshipOverlay = relationshipEnter.overlay.merge(relationshipOverlay);
relationshipText = svg.selectAll('.relationship .text');
relationshipText = relationshipEnter.text.merge(relationshipText);
}
function version() {
return VERSION;
}
function zoomFit(transitionDuration) {
var bounds = svg.node().getBBox(),
parent = svg.node().parentElement.parentElement,
fullWidth = parent.clientWidth,
fullHeight = parent.clientHeight,
width = bounds.width,
height = bounds.height,
midX = bounds.x + width / 2,
midY = bounds.y + height / 2;
if (width === 0 || height === 0) {
return; // nothing to fit
}
svgScale = 0.85 / Math.max(width / fullWidth, height / fullHeight);
svgTranslate = [fullWidth / 2 - svgScale * midX, fullHeight / 2 - svgScale * midY];
svg.attr('transform', 'translate(' + svgTranslate[0] + ', ' + svgTranslate[1] + ') scale(' + svgScale + ')');
// smoothTransform(svgTranslate, svgScale);
}
init(_selector, _options);
return {
appendRandomDataToNode: appendRandomDataToNode,
neo4jDataToD3Data: neo4jDataToD3Data,
randomD3Data: randomD3Data,
size: size,
updateWithD3Data: updateWithD3Data,
updateWithNeo4jData: updateWithNeo4jData,
version: version
};
}
export default Neo4jD3;
\ No newline at end of file
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论