Reputation: 3298
I want to use D3 to create augmented svg-pathes and filling them. Augmented pathes are pathes, that contain multiple parts using different interpolation methods. Have a look at the following example (execute the code to see the svg):
p1 = [
[10,10],
[10,190],
[190,190]
];
p2 = [
[190,190],
[50,50],
[190,20]
];
p3 = [
[190,20],
[190, 10]
];
p4 = [
[190,10],
[100,20],
[10,10]
];
var svg = d3.select('svg')
.attr("width", 200)
.attr("height", 200)
.attr("viewBox", "0 0 200 200");
var line = d3.svg.line().interpolate("linear");
var spline = d3.svg.line().interpolate("basis");
svg.append("path")
.attr("d", function(){
return line(p1) + spline(p2) + line(p3) + spline(p4)
})
.attr("fill", "none")
.attr("stroke-width", 1)
.attr("stroke", "black");
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>
<svg>
</svg>
<svg viewBox="0 0 200 200" height="190" width="190">
<path stroke="black" stroke-width="1" fill="purple" d="M10,10L10,190L190,190M190,190L166.66666666666666,166.66666666666666C143.33333333333331,143.33333333333331,96.66666666666666,96.66666666666666,96.66666666666666,68.33333333333333C96.66666666666666,39.99999999999999,143.33333333333331,29.999999999999996,166.66666666666666,24.999999999999996L190,20M190,20L190,10M190,10L174.99999999999997,11.666666666666664C160,13.333333333333332,130,16.666666666666664,99.99999999999999,16.666666666666664C69.99999999999999,16.666666666666664,39.99999999999999,13.333333333333332,24.999999999999996,11.666666666666666L10,10"></path></svg>
The shape is not recognized as one shape and thus not filled correctly. (By the way: it works when using only one spline and only one linear interpolated part.) One possibility to solve that problem, would be to remove the unnessesary movement commands inserted by D3. However, I can't believe, that this is the only solution. There must be a simpler and cleaner solution. Probably I'm misinterpreting how to use D3. Can anyone give me a clue?
Edit: What I expect the filled shape to look like:
<svg viewBox="0 0 200 200" height="190" width="190">
<path stroke="black" stroke-width="1" fill="purple"
d="M10,10L10,190L190,190L166.66666666666666,166.66666666666666C143.33333333333331,143.33333333333331,96.66666666666666,96.66666666666666,96.66666666666666,68.33333333333333C96.66666666666666,39.99999999999999,143.33333333333331,29.999999999999996,166.66666666666666,24.999999999999996L190,20L190,10L174.99999999999997,11.666666666666664C160,13.333333333333332,130,16.666666666666664,99.99999999999999,16.666666666666664C69.99999999999999,16.666666666666664,39.99999999999999,13.333333333333332,24.999999999999996,11.666666666666666L10,10"></path></svg>
Upvotes: 0
Views: 156
Reputation: 108517
You can't just concatenate the paths together. Each one starts with a move to
command (M10,10
or something like that). This will produce an "open" path that you can't be filled correctly. Easy fix, is to just remove the move to
command on all but the first path:
<!DOCTYPE html>
<html>
<head>
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>
</head>
<body>
<svg>
</svg>
<script>
p1 = [
[10, 10],
[10, 190],
[190, 190]
];
p2 = [
[190, 190],
[50, 50],
[190, 20]
];
p3 = [
[190, 20],
[190, 10]
];
p4 = [
[190, 10],
[100, 20],
[10, 10]
];
var svg = d3.select('svg')
.attr("width", 200)
.attr("height", 200)
.attr("viewBox", "0 0 200 200");
var line = d3.svg.line().interpolate("linear");
var spline = d3.svg.line().interpolate("basis");
svg.append("path")
.attr("d", function() {
var s1 = line(p1),
s2 = spline(p2),
s3 = line(p3),
s4 = spline(p4);
s2 = s2.substring(s2.indexOf("L"), s2.length);
s3 = s3.substring(s3.indexOf("L"), s3.length);
s4 = s4.substring(s4.indexOf("L"), s4.length);
return s1 + s2 + s3 + s4;
})
.attr("fill", "purple")
.attr("stroke-width", 1)
.attr("stroke", "black")
</script>
</body>
</html>
Upvotes: 1