UNPKG

neo4jd3-graph

Version:

The neo4jd3-graph npm package is a tool designed for visualizing Neo4j graph data. This package utilizes the power of D3.js (version 4.2.1) for rendering interactive and dynamic graphs representing relationships within Neo4j databases. The visualization i

832 lines (831 loc) 32.8 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); // @ts-ignore var d3 = require("d3"); require("./styles/styles.css"); require("font-awesome/css/font-awesome.css"); var interface_1 = require("./interfaces/interface"); function Neo4jD3() { var container, info, node, nodes, relationship, relationshipOutline, relationshipOverlay, relationshipText, relationships, selector, simulation, svg, svgNodes, svgRelationships, svgScale, svgTranslate, classes2colors = {}, justLoaded = false, numClasses = 0, options = { arrowSize: 4, colors: interface_1.colors, highlight: undefined, iconMap: interface_1.fontAwesomeIcons, icons: undefined, imageMap: {}, images: undefined, infoPanel: true, minCollision: undefined, neo4jData: undefined, neo4jDataUrl: undefined, nodeOutlineFillColor: undefined, nodeRadius: 25, relationshipColor: 'red', zoomFit: false, }, VERSION = '1.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 table = info.append('table').style('border-collapse', 'collapse').style('width', '100%'); var row = table.append('tr'); if (!value) { row .append('td') .attr('class', cls) .style('border', '1px solid #dddddd') .style('padding', '8px') .style('width', '200px') .style('text-wrap', 'no-wrap') .html('<strong>Name</strong>'); row .append('td') .style('border', '1px solid #dddddd') .style('padding', '8px') .style('width', 'auto') .style('text-wrap', 'no-wrap') .html('<strong>' + property + '</strong>'); row .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'; }); } else { row .append('td') .attr('class', cls) .style('border', '1px solid #dddddd') .style('padding', '8px') .style('width', '200px') .style('text-wrap', 'no-wrap') .html('<strong>' + property + '</strong>'); row .append('td') .style('border', '1px solid #dddddd') .style('padding', '8px') .style('width', 'auto') .style('text-wrap', 'no-wrap') .html('<strong>' + value + '</strong>'); } } 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).toString()) + '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); } if (typeof options.onRelationshipMouseEnter === 'function') { options.onRelationshipMouseEnter(d); } }) .on('mouseleave', function (d) { if (info) { clearInfo(d); } if (typeof options.onRelationshipMouseLeave === 'function') { options.onRelationshipMouseLeave(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[numClasses % options.colors.length]; classes2colors[cls] = color; numClasses++; } return color; } function class2darkenColor(cls) { return d3.rgb(class2color(cls)).darker(1); } function clearInfo(d) { info.html(''); } function color() { return options.colors[(options.colors.length * Math.random()) << 0]; } 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 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 createGraph(_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(); } 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); simulation // .force('x', 0.00111) // .force('y', 0.000000001) .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) { 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 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 }; var 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', 'id', d.id); Object.keys(d.properties).forEach(function (property) { appendInfoElementProperty('property', property, 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 && parent.clientWidth ? parent.clientWidth : '100vw', fullHeight = parent && parent.clientHeight ? parent.clientHeight : '100vh', width = bounds.width, height = bounds.height, midX = bounds.x + width / 2, midY = bounds.y + height / 2; if (width === 0 || height === 0) { return; } 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 + ')'); } return { appendRandomDataToNode: appendRandomDataToNode, neo4jDataToD3Data: neo4jDataToD3Data, randomD3Data: randomD3Data, size: size, updateWithD3Data: updateWithD3Data, updateWithNeo4jData: updateWithNeo4jData, version: version, createGraph: createGraph, }; } exports.default = Neo4jD3();