From 4988310dba01672f43b4aca266bbfca8b7f7eb65 Mon Sep 17 00:00:00 2001 From: orctom Date: Mon, 15 Apr 2019 00:39:37 +0800 Subject: [PATCH] #316 Support markers at start and midpoint of edges --- demo/arrows.html | 21 +++++++++++++++++++++ demo/user-defined.html | 10 ++++++++-- lib/arrows.js | 14 ++++++++++---- lib/create-edge-paths.js | 12 ++++++++++++ lib/lodash.js | 3 ++- lib/render.js | 2 ++ 6 files changed, 55 insertions(+), 7 deletions(-) diff --git a/demo/arrows.html b/demo/arrows.html index c9632f58..dabb833f 100644 --- a/demo/arrows.html +++ b/demo/arrows.html @@ -48,6 +48,27 @@

Dagre D3 Demo: Arrows

}); }); +// Reverse direction (arrowtail) +["normal", "vee"].forEach(function(arrowtail) { + g.setNode(arrowtail + "3", { label: " " }); + g.setNode(arrowtail + "4", { label: " " }); + g.setEdge(arrowtail + "3", arrowtail + "4", { + arrowhead: "undirected", + arrowtail: arrowtail, + label: arrowtail + " (arrowtail)" + }); +}); + // Arrowhead in the middle (arrowmid) +["normal", "vee"].forEach(function(arrowmid) { + g.setNode(arrowmid + "5", { label: " " }); + g.setNode(arrowmid + "6", { label: " " }); + g.setEdge(arrowmid + "5", arrowmid + "6", { + arrowhead: "undirected", + arrowmid: arrowmid, + label: arrowmid + " (arrowmid)" + }); +}); + var svg = d3.select("svg"), inner = svg.select("g"); diff --git a/demo/user-defined.html b/demo/user-defined.html index 8593ff6a..7a2b9ae1 100644 --- a/demo/user-defined.html +++ b/demo/user-defined.html @@ -79,19 +79,25 @@

Dagre D3 Demo: User-defined Shapes and Arrows

}; // Add our custom arrow (a hollow-point) +// Note we have to draw it upside down if this is a +// reverse direction arrow (arrowtail) render.arrows().hollowPoint = function normal(parent, id, edge, type) { + var invert = id.indexOf("arrowtail") !== -1; var marker = parent.append("marker") .attr("id", id) .attr("viewBox", "0 0 10 10") - .attr("refX", 9) + .attr("refX", invert ? 0 : 9) .attr("refY", 5) .attr("markerUnits", "strokeWidth") .attr("markerWidth", 8) .attr("markerHeight", 6) .attr("orient", "auto"); + var movements = (invert ? + "M 10 0 L 0 5 L 10 10 z" : + "M 0 0 L 10 5 L 0 10 z"); var path = marker.append("path") - .attr("d", "M 0 0 L 10 5 L 0 10 z") + .attr("d", movements) .style("stroke-width", 1) .style("stroke-dasharray", "1,0") .style("fill", "#fff") diff --git a/lib/arrows.js b/lib/arrows.js index e95cc628..db766ff8 100644 --- a/lib/arrows.js +++ b/lib/arrows.js @@ -1,4 +1,5 @@ -var util = require("./util"); +var _ = require("./lodash"), + util = require("./util"); module.exports = { "default": normal, @@ -8,18 +9,22 @@ module.exports = { }; function normal(parent, id, edge, type) { + var invert = _.some(id, "arrowtail"); var marker = parent.append("marker") .attr("id", id) .attr("viewBox", "0 0 10 10") - .attr("refX", 9) + .attr("refX", invert ? 0 : 9) .attr("refY", 5) .attr("markerUnits", "strokeWidth") .attr("markerWidth", 8) .attr("markerHeight", 6) .attr("orient", "auto"); + var movements = (invert ? + "M 10 0 L 0 5 L 10 10 z" : + "M 0 0 L 10 5 L 0 10 z"); var path = marker.append("path") - .attr("d", "M 0 0 L 10 5 L 0 10 z") + .attr("d", movements) .style("stroke-width", 1) .style("stroke-dasharray", "1,0"); util.applyStyle(path, edge[type + "Style"]); @@ -29,10 +34,11 @@ function normal(parent, id, edge, type) { } function vee(parent, id, edge, type) { + var invert = _.some(id, "arrowtail"); var marker = parent.append("marker") .attr("id", id) .attr("viewBox", "0 0 10 10") - .attr("refX", 9) + .attr("refX", invert ? 0 : 9) .attr("refY", 5) .attr("markerUnits", "strokeWidth") .attr("markerWidth", 8) diff --git a/lib/create-edge-paths.js b/lib/create-edge-paths.js index 0b839ace..7a3a2571 100644 --- a/lib/create-edge-paths.js +++ b/lib/create-edge-paths.js @@ -36,11 +36,19 @@ function createEdgePaths(selection, g, arrows) { .each(function(e) { var edge = g.edge(e); edge.arrowheadId = _.uniqueId("arrowhead"); + edge.arrowmidId = _.uniqueId("arrowmid"); + edge.arrowtailId = _.uniqueId("arrowtail"); var domEdge = d3.select(this) .attr("marker-end", function() { return "url(" + makeFragmentRef(location.href, edge.arrowheadId) + ")"; }) + .attr("marker-mid", function() { + return "url(" + makeFragmentRef(location.href, edge.arrowmidId) + ")"; + }) + .attr("marker-start", function() { + return "url(" + makeFragmentRef(location.href, edge.arrowtailId) + ")"; + }) .style("fill", "none"); util.applyTransition(domEdge, g) @@ -54,7 +62,11 @@ function createEdgePaths(selection, g, arrows) { .each(function(e) { var edge = g.edge(e); var arrowhead = arrows[edge.arrowhead]; + var arrowmid = arrows[edge.arrowmid]; + var arrowtail = arrows[edge.arrowtail]; arrowhead(d3.select(this), edge.arrowheadId, edge, "arrowhead"); + arrowmid(d3.select(this), edge.arrowmidId, edge, "arrowhead"); + arrowtail(d3.select(this), edge.arrowtailId, edge, "arrowhead"); }); return svgPaths; diff --git a/lib/lodash.js b/lib/lodash.js index 6c26fe26..8ae6e977 100644 --- a/lib/lodash.js +++ b/lib/lodash.js @@ -12,7 +12,8 @@ if (typeof require === "function") { pick: require("lodash/pick"), has: require("lodash/has"), range: require("lodash/range"), - uniqueId: require("lodash/uniqueId") + uniqueId: require("lodash/uniqueId"), + some: require("lodash/some") }; } catch (e) { diff --git a/lib/render.js b/lib/render.js index 36d235c7..22aa2f2c 100644 --- a/lib/render.js +++ b/lib/render.js @@ -88,6 +88,8 @@ var NODE_DEFAULT_ATTRS = { var EDGE_DEFAULT_ATTRS = { arrowhead: "normal", + arrowmid: "undirected", + arrowtail: "undirected", curve: d3.curveLinear };