Thick Bezier curves in SVG without artifacts

I am trying to draw thick bezier lines (for a custom Sanki diagram ). I use SVG Paths with Bezier curves in the form C x1 y1, x2 y2, xy . I use stroke , not fill , so they have a constant width (and can represent threads).

It works very well if the lines are thin or the vertical difference is relatively low. However, if they are very thick, I get some unpleasant artifacts (like horns) - see the lower right curve in the figure below:

enter image description here

Source: http://jsfiddle.net/stared/83jr5fub/

Is there any way to avoid artifacts, i.e.:

  • make sure that nothing remains to the left of x1 or to the right of x ,
  • actual width in left and right stroke-width match?
+5
source share
2 answers

I think the best solution in your case (with the given path) is to make your path closed and use its fill property.

To do this, you need to do lineTo(0, strokeWidth) at the end of your BezierCurveTo , and then redraw the bezierCurve differently:

 var svg = d3.select("#chart"); var data = [ {t: 5, dy: 10}, {t: 5, dy: 20}, {t: 5, dy: 40}, {t: 20, dy: 10}, {t: 20, dy: 20}, {t: 20, dy: 40}, {t: 50, dy: 10}, {t: 50, dy: 20}, {t: 50, dy: 40}, ]; var ctrl = 10; var dx = 40; var spacing = 100; var colors = d3.scale.category10(); svg .attr("width", 4 * spacing) .attr("height", 4 * spacing); svg.selectAll("path") .data(data) .enter() .append("path") .attr("d", function (d, i) { var x1 = spacing + spacing * (i % 3); var y1 = spacing + spacing * Math.floor(i / 3); return "M" + x1 + "," + y1 + "c" + ctrl + "," + 0 + " " + (dx - ctrl) + "," + d.dy + " " + dx + "," + d.dy + // move down for the wanted width "l" + (0) + "," + (dt) + // negate all values "c" + (ctrl * -1) + "," + 0 + " " + ((dx - ctrl) * -1) + "," + (d.dy * -1) + " " + (dx * -1) + "," + (d.dy * -1); }) .style("fill", colors(0)) 
 <script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script> <svg id="chart"></svg> 

And since an animation of more than 10 thousand words shows here what is happening and why it cannot be called a browser error:

 @keyframes dash { from { stroke-dashoffset: -10%; } to { stroke-dashoffset: 90%; } } @-webkit-keyframes dash { from { stroke-dashoffset: -10%; } to { stroke-dashoffset: 90%; } } #dashed{ animation : dash 12s linear infinite; } 
 <svg height="200" width="200" id="chart" viewBox="290 260 100 100"> <path id="dashed" style="fill: none; stroke: rgb(31, 119, 180); stroke-width: 50; stroke-dasharray: 3, 3;" d="M300,300c10,0 30,40 40,40"></path> <path style="fill: none; stroke: black;" d="M300,300c10,0 30,40 40,40"> </path></svg> 
+8
source
Kaido gave an excellent and complete answer for why the SVG path with a thick stroke width is displayed with artifacts and how to avoid this. I will try to provide a little more information that is typical for D3.js Sankey diagrams, as I recently encountered the same problem as Peter Migdal.

Original Sankey Chart Code

(from Sankey.js in this Sankey example , which is similar to the example mentioned by Peter Migdal)

  // regular forward node var x0 = d.source.x + d.source.dx, x1 = d.target.x, xi = d3.interpolateNumber(x0, x1), x2 = xi(curvature), x3 = xi(1 - curvature), y0 = d.source.y + d.sy + d.dy / 2, y1 = d.target.y + d.ty + d.dy / 2; return "M" + x0 + "," + y0 + "C" + x2 + "," + y0 + " " + x3 + "," + y1 + " " + x1 + "," + y1; 

Modified code

  // regular forward node var x0 = d.source.x + d.source.dx, x1 = d.target.x, xi = d3.interpolateNumber(x0, x1), x2 = xi(curvature), x3 = xi(1 - curvature), y0 = d.source.y + d.sy, y1 = d.target.y + d.ty; return "M" + x0 + "," + y0 + "C" + x2 + "," + y0 + " " + x3 + "," + y1 + " " + x1 + "," + y1 // move down for the wanted width + "l" + 0 + "," + d.dy // draw another path below mirroring the top + "C" + x3 + "," + (y1 + d.dy) + " " + x2 + "," + (y0 + d.dy) + " " + x0 + "," + (y0 + d.dy); 

Then you will also need to change your css:

  • stroke: none
  • set fill color

and remove any D3 code that sets the stroke width of the HTML elements.

+1
source

Source: https://habr.com/ru/post/1238119/


All Articles