UNPKG

dagre-d3v4

Version:
136 lines (111 loc) 3.76 kB
"use strict"; var _ = require("./lodash"), intersectNode = require("./intersect/intersect-node"), util = require("./util"), d3 = require("./d3"); module.exports = createEdgePaths; function createEdgePaths(selection, g, arrows) { var svgPathsUpdate = selection.selectAll("g.edgePath") .data(g.edges(), function(e) { return util.edgeToId(e); }) .classed("update", true); var svgPathsEnter = enter(svgPathsUpdate, g); exit(svgPathsUpdate, g); var svgPathsMerge = svgPathsEnter.merge(svgPathsUpdate); util.applyTransition(svgPathsMerge, g) .style("opacity", 1); // Save DOM element in the path group, and set ID and class svgPathsMerge.each(function(e) { var domEdge = d3.select(this); var edge = g.edge(e); edge.elem = this; if (edge.id) { domEdge.attr("id", edge.id); } util.applyClass(domEdge, edge["class"], (domEdge.classed("update") ? "update " : "") + "edgePath"); }); svgPathsMerge.selectAll("path.path") .each(function(e) { var edge = g.edge(e); edge.arrowheadId = _.uniqueId("arrowhead"); var domEdge = d3.select(this) .attr("marker-end", function() { return "url(" + makeFragmentRef(location.href, edge.arrowheadId) + ")"; }) .style("fill", "none"); util.applyTransition(domEdge, g) .attr("d", function(e) { return calcPoints(g, e); }); util.applyStyle(domEdge, edge.style); }); /* -FIX- d3v4: during render updates, can we be smarter about this remove-and-recreate? */ svgPathsMerge.selectAll("defs *").remove(); svgPathsMerge.selectAll("defs") .each(function(e) { var edge = g.edge(e), arrowhead = arrows[edge.arrowhead]; arrowhead(d3.select(this), edge.arrowheadId, edge, "arrowhead"); }); return svgPathsMerge; } function makeFragmentRef(url, fragmentId) { var baseUrl = url.split("#")[0]; return baseUrl + "#" + fragmentId; } function calcPoints(g, e) { var edge = g.edge(e), tail = g.node(e.v), head = g.node(e.w), points = edge.points.slice(1, edge.points.length - 1); points.unshift(intersectNode(tail, points[0])); points.push(intersectNode(head, points[points.length - 1])); return createLine(edge, points); } function createLine(edge, points) { var line = d3.line() .x(function(d) { return d.x; }) .y(function(d) { return d.y; }); if (edge.hasOwnProperty("curve")) { line.curve(edge.curve); } return line(points); } function getCoords(elem) { var bbox = elem.getBBox(), matrix = elem.ownerSVGElement.getScreenCTM() .inverse() .multiply(elem.getScreenCTM()) .translate(bbox.width / 2, bbox.height / 2); return { x: matrix.e, y: matrix.f }; } function enter(svgPaths, g) { var svgPathsEnter = svgPaths.enter() .append("g") .attr("class", "edgePath") .style("opacity", 0); svgPathsEnter.append("path") .attr("class", "path") .attr("d", function(e) { var edge = g.edge(e), sourceElem = g.node(e.v).elem, points = _.range(edge.points.length).map(function() { return getCoords(sourceElem); }); return createLine(edge, points); }); svgPathsEnter.append("defs"); return svgPathsEnter; } function exit(svgPaths, g) { var svgPathExit = svgPaths.exit(); util.applyTransition(svgPathExit, g) .style("opacity", 0) .remove(); util.applyTransition(svgPathExit.select("path.path"), g) .attr("d", function(e) { var source = g.node(e.v); if (source) { var points = _.range(this.getTotalLength()).map(function() { return source; }); return createLine({}, points); } else { return d3.select(this).attr("d"); } }); }