I would like to know if there is an alternative to applying the "stroke-dasharray"
to a path. What I'm trying to do is add a dashed line to a certain range in the path. The thing is that the line is not straight. And I want to avoid creating two lines using the same data within different range. Does anyone have an idea?
I would like to know if there is an alternative to applying the "stroke-dasharray"
to a path. What I'm trying to do is add a dashed line to a certain range in the path. The thing is that the line is not straight. And I want to avoid creating two lines using the same data within different range. Does anyone have an idea?
-
2
You can do this with
stroke-dasharray
-- one long stroke for the first uninterrupted part, then strokes and dashes, then another long stroke for the second uninterrupted part. – Lars Kotthoff Commented Jan 25, 2016 at 19:08 - With stroke array i have to give the number of pixel for solid than the number of pixel for the dashed. Yet my line is not straight so it won't work ? – skip87 Commented Jan 25, 2016 at 19:11
- 3 The strokes are relative to the length of the line, so it doesn't matter whether it's curved or straight. – Lars Kotthoff Commented Jan 25, 2016 at 19:14
- ok i"ll let you know if it's working thanks – skip87 Commented Jan 25, 2016 at 19:16
- Similar question: stackoverflow./questions/24725587/… – Mark Commented Jan 25, 2016 at 20:27
2 Answers
Reset to default 8I linked this question which provides a pretty good overview of how stroke-dasharray
works, but the interesting part of this question bees, how can I dash over a specific section of the line? With that in mind, say we have a line from 0 to 10 and we want to dash it from 2.5 to 7:
<!DOCTYPE html>
<meta charset="utf-8">
<style>
body {
font: 10px sans-serif;
}
.axis path,
.axis line {
fill: none;
stroke: #000;
shape-rendering: crispEdges;
}
.x.axis path {
display: none;
}
.line {
fill: none;
stroke: steelblue;
stroke-width: 1.5px;
}
</style>
<body>
<script src="//d3js/d3.v4.min.js"></script>
<script>
var margin = {
top: 20,
right: 20,
bottom: 30,
left: 50
},
width = 960 - margin.left - margin.right,
height = 500 - margin.top - margin.bottom;
var data = d3.range(11).map(function(d, i) {
return {
x: i,
y: Math.random() * 100
};
});
var x = d3.scaleLinear()
.range([0, width])
.domain([0, 10]);
var y = d3.scaleLinear()
.range([height, 0])
.domain([0, 100]);
var xAxis = d3.axisBottom()
.scale(x);
var yAxis = d3.axisLeft()
.scale(y);
var line = d3.line()
.x(function(d) {
return x(d.x);
})
.y(function(d) {
return y(d.y);
})
.curve(d3.curveBasis);
var svg = d3.select("body").append("svg")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
svg.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(xAxis);
svg.append("g")
.attr("class", "y axis")
.call(yAxis)
var p = svg.append("path")
.datum(data)
.attr("class", "line")
.attr("d", line);
// draw dashed from 2.7 to 7 in the X domain
var dashBetweenX = [2.5, 7]
path = p.node(),
totalLen = path.getTotalLength();
// find the corresponding line lengths
var dashBetweenL = dashBetweenX.map(function(d,i){
var beginning = 0,
end = totalLen,
target = null,
d = x(d);
// find the line lengths the correspond to our X values
// stolen from @duopixel from http://bl.ocks/duopixel/3824661
while (true){
target = Math.floor((beginning + end) / 2);
pos = path.getPointAtLength(target);
if ((target === end || target === beginning) && pos.x !== d) {
break;
}
if (pos.x > d) end = target;
else if (pos.x < d) beginning = target;
else break; //position found
}
return target;
})
// draw the dashes
var sd = dashBetweenL[0],
dp = dashBetweenL[0],
count = 0;
while (dp < dashBetweenL[1]){
dp += 2;
sd += ", 2";
count++;
}
// per answer below needs odd number of dash array
if (count % 2 == 0)
sd += ", 2";
sd += ", " + (totalLen - dashBetweenL[1]);
p.attr("stroke-dasharray", sd);
</script>
</body>
</html>
@Mark has a partially working solution for me. I had to perform one additional check after adding the dashes. If the number of dashes added was even, the line after the dash would not render.
Modifying the section as follows fixed it for me:
let count = 0;
while (dp < dashBetweenL[1]) {
count ++;
dp += 4;
sd += ", 4";
}
if (count % 2 == 0) {
sd += ", 4, " + (totalLen - dashBetweenL[1]);
} else {
sd += ", " + (totalLen - dashBetweenL[1]);
}
p.attr("stroke-dasharray", sd);
Truthfully, I'm having a hard time seeing why it was necessary but appears to be working perfectly.