<!DOCTYPE html> <meta charset="utf-8"> <head> <title>Page Title</title> <style> circle { fill: steelblue; stroke: #fff; stroke-width: 1px; } path { fill: none; stroke: #000; stroke-width: 0px; } </style> </head> <body> <script src="https://d3js.org/d3.v5.min.js"></script> <div id='arrows'></div> <script> var arr_div = document.getElementById("arrows"); var width = arr_div.clientWidth; var height = arr_div.clientHeight; function arrows(svg_selector = "", path_id = "", segments = 8, thickness = 5) { console.log(svg_selector); if (svg_selector === "") { var svg = d3.select("svg"); } else { var svg = d3.select(svg_selector); } if (path_id === "") { var path = svg.select("path").node(); } else { var path = svg.select("#"+path_id).node(); } console.log("svg "+svg); console.log(path); var l = path.getTotalLength(); var segs = 8; var seg_l = l / segs; var thickness = 5; console.log(l, seg_l) for (var i = 0; i < segs; i++) { var start = i * seg_l; var end = (i + 1) * seg_l; console.log(i, start, start); ar = new ArowOnPath(path, start, end); svg.append("path") .attr("d", ar.toString()) .attr("style", "fill:" + getRandomColorRgb()); } } d3.svg('path.svg').then(function (svg) { svgnode = document.importNode(svg.documentElement, true); console.log(svgnode); d3.select("div#arrows").node().append(svgnode); arrows("","path905"); }); /* var svg = d3.select("svgobject") .attr("width", 100) .attr("height", 500) .attr("viewBox", "0 0 500 250"); var path = svg.append("path") .attr("d", "m 148.72841,44.122751 c 24.39295,-6.887543 34.01192,11.961379 34.04221,25.595869 0.0303,13.63449 -22.99535,32.36853 -35.4467,32.64203 C 134.87257,102.63414 115.7832,72.134311 106.84906,60.736038 97.914925,49.337765 72.784255,30.266031 70.522257,21.15664 c -2.261998,-9.109391 -7.159135,-21.69117332 2.72304,-27.0895314 9.882175,-5.3983576 32.767453,-2.1532373 38.602383,-1.1928849 5.83492,0.9603523 14.42644,30.7694983 6.13055,38.7549313 -8.29588,7.985433 -41.770833,12.528576 -48.201026,12.493596 -6.430193,-0.03498 -22.799636,11.961369 -22.829921,25.595869 -0.03028,13.6345 23.982951,32.30489 39.33273,32.64203 15.349777,0.33714 38.055457,-51.350355 62.448397,-58.237899 z" ); */ function getRandomColorRgb() { let red = Math.floor(Math.random() * 256); let green = Math.floor(Math.random() * 256); let blue = Math.floor(Math.random() * 256); return `rgb(${red}, ${green}, ${blue})`; } function pointDist(point, distance, rad) { return { x: point.x + distance * Math.cos(rad), y: point.y + distance * Math.sin(rad) }; } // from https://github.com/d3/d3-shape/blob/master/src/curve/natural.js function controlPoints(x) { var i, n = x.length - 1, m, a = new Array(n), b = new Array(n), r = new Array(n); a[0] = 0, b[0] = 2, r[0] = x[0] + 2 * x[1]; for (i = 1; i < n - 1; ++i) a[i] = 1, b[i] = 4, r[i] = 4 * x[i] + 2 * x[i + 1]; a[n - 1] = 2, b[n - 1] = 7, r[n - 1] = 8 * x[n - 1] + x[n]; for (i = 1; i < n; ++i) m = a[i] / b[i - 1], b[i] -= m, r[i] -= m * r[i - 1]; a[n - 1] = r[n - 1] / b[n - 1]; for (i = n - 2; i >= 0; --i) a[i] = (r[i] - a[i + 1]) / b[i]; b[n - 1] = (x[n] + a[n - 1]) / 2; for (i = 0; i < n - 1; ++i) b[i] = 2 * x[i + 1] - a[i + 1]; return [a, b]; } class ArowOnPath { constructor(path, start, end, parts = 3, thickness = 5, angle = 2, padding = 1) { this.path = path; this.angle = angle; this.thickness = thickness; var length = end - start; var partlen = (length - (2 * padding)) / (2 * parts); console.log("ArrowOnPath", start, end, partlen); this.p = [this.pointsAt(start + padding, (-1 * padding))]; for (var i = 1; i < (2 * parts); i++) { this.p.push(this.pointsAt(start + (i * partlen))); } this.p.push(this.pointsAt(start + length - padding, (1 * padding))); } pointAngle(length) { var p1 = this.path.getPointAtLength(length); var p2 = this.path.getPointAtLength(length + 0.01); if (p1.x == p2.x && p1.y == p2.y) { p1 = this.path.getPointAtLength(length - 0.01); } console.log(p1, p2); return Math.atan2((p2.y - p1.y), (p2.x - p1.x)); } pointsAt(length, angleoffset = 0) { var m = this.path.getPointAtLength(length); var m_angle = this.pointAngle(length + angleoffset) console.log("a", m_angle); var a = { x: m.x + (this.thickness * Math.cos(m_angle + this.angle)) , y: m.y + (this.thickness * Math.sin(m_angle + this.angle)) }; var b = { x: m.x + (this.thickness * Math.cos(m_angle - this.angle)) , y: m.y + (this.thickness * Math.sin(m_angle - this.angle)) }; return { a: a, m: m, b: b } } p2s(point) { return point.x.toString() + "," + point.y.toString(); } d3path() { var path = d3.path(); var i = 0 path.moveTo(this.p[i].m.x, this.p[i].m.y); path.lineTo(this.p[i].a.x, this.p[i].a.y); var nat = d3.curveNatural(path); nat.lineStart(); for (var i = 0; i < this.p.length; i++) { nat.point(this.p[i].a.x, this.p[i].a.y); } var px = controlPoints(nat._x), py = controlPoints(nat._y); var n = this.p.length; var x = nat._x, y = nat._y; for (var i0 = 0, i1 = 1; i1 < n; ++i0, ++i1) { path.bezierCurveTo(px[0][i0], py[0][i0], px[1][i0], py[1][i0], x[i1], y[i1]); } i = this.p.length - 1; path.lineTo(this.p[i].m.x, this.p[i].m.y); path.lineTo(this.p[i].b.x, this.p[i].b.y); nat.lineStart(); for (var i = this.p.length - 1; i >= 0; --i) { nat.point(this.p[i].b.x, this.p[i].b.y); } var px = controlPoints(nat._x), py = controlPoints(nat._y); var n = this.p.length; var x = nat._x, y = nat._y; for (var i0 = 0, i1 = 1; i1 < n; ++i0, ++i1) { path.bezierCurveTo(px[0][i0], py[0][i0], px[1][i0], py[1][i0], x[i1], y[i1]); } path.closePath(); return path; } toString() { return this.d3path().toString(); } } /*var s = path.node() */ </script> </body>