I've modified the y.domain of my D3 bar chart so it starts at a value above zero. However, I want to add a little "zig zag line" to indicate this, as in the picture below.

How could I do this in D3? Many thanks!
I'd just hack this on by adding another path to the y axis:
// define how much space you'd like to create the axis "break" in
var axisBreakSpace = 50;
// Add the X Axis, with the space
svg.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + (height + axisBreakSpace) + ")")
.call(xAxis);
// Add the Y Axis, normally
var yG = svg.append("g")
.attr("class", "y axis")
.call(yAxis);
// add the zigzags path
yG.append("path")
.attr("d", function(){
var numZags = 10, // number of zigzags
zagDist = (axisBreakSpace - 5) / numZags; // y distance on each zig or zag, -5 is a bit of space to finish it off
// build the path at
var curZig = height,
d = "M0," + curZig;
for (var i = 0; i < numZags; i++){
curZig += zagDist;
d += (i % 2 === 0) ? " L10," + curZig : " L-10," + curZig;
}
// finish it off to the x-axis
d += " L0," + (height + axisBreakSpace);
return d;
});
Full working code sample:
<!DOCTYPE html>
<meta charset="utf-8">
<style>
/* set the CSS */
body {
font: 12px Arial;
}
path {
stroke: steelblue;
stroke-width: 2;
fill: none;
}
.axis path,
.axis line {
fill: none;
stroke: grey;
stroke-width: 1;
shape-rendering: crispEdges;
}
</style>
<body>
<!-- load the d3.js library -->
<script src="http://d3js.org/d3.v3.min.js"></script>
<script>
// Set the dimensions of the canvas / graph
var margin = {
top: 30,
right: 20,
bottom: 100,
left: 50
},
width = 600 - margin.left - margin.right,
height = 270 - margin.top - margin.bottom,
axisBreakSpace = 50;
// Set the ranges
var x = d3.scale.linear().range([0, width])
.domain([0, 10]);
var y = d3.scale.linear().range([height, 0])
.domain([200,1000]);
// Define the axes
var xAxis = d3.svg.axis().scale(x)
.orient("bottom")
var yAxis = d3.svg.axis().scale(y)
.orient("left");
// Define the line
var line = d3.svg.line()
.x(function(d) {
return x(d.x);
})
.y(function(d) {
return y(d.y);
});
// Adds the svg canvas
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 + ")");
var data = d3.range(10).map(function(d){
return {
x: d,
y: (Math.random() * 800) + 200
}
});
// Add the valueline path.
svg.append("path")
.attr("class", "line")
.attr("d", line(data));
// Add the X Axis
svg.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + (height + axisBreakSpace) + ")")
.call(xAxis);
// Add the Y Axis
var yG = svg.append("g")
.attr("class", "y axis")
.call(yAxis);
yG.append("path")
.attr("d", function(){
var numZags = 10,
zagDist = (axisBreakSpace - 5) / numZags;
var curZig = height,
d = "M0," + curZig;
for (var i = 0; i < numZags; i++){
curZig += zagDist;
d += (i % 2 === 0) ? " L10," + curZig : " L-10," + curZig;
}
d += " L0," + (height + axisBreakSpace);
return d;
});
</script>
</body>
I would create some data and pass it to the D3 library. Something similar to this :
var data = [{
x1: xAxisSTARTPOINTX, //start
y1; xAxisSTARTPOINTY,
x2: firstXPointOnZigZag,
y2; firstYPointOnZigZag},{
.
.
. },{
x1: lastXPointOnZigZag, //end
y1; lastYPointOnZigZag,
x2: yAxisSTARTPOINTX,
y2; yAxisSTARTPOINTY}
}]
The values you put between will be the points on the zig zag which you can make up/generate.
Then pass this to this :
d3.select(container).data(data).enter().append('path')
.attr('x1', function(d){ return d.x1})
.attr('y1', function(d){ return d.y1})
.attr('x2', function(d){ return d.x2})
.attr('y2', function(d){ return d.y2})
.style('stroke','black');
You could generate the points yourself so you can change how many 'zigzags' you want by changing 'i' in the for loop.
A function to create points, something similar to this :
function createPoints(xAxisStartPoint, yAxisStartPoint){ //pass two arrays
var xAxisStartX = xAxisStartPoint[0], //xAxisStartPointX
xAxisStartY = xAxisStartPoint[1], //xAxisStartPointY
yAxisStartX = yAxisStartPoint[0], //xAxisStartPointX
yAxisStartY = yAxisStartPoint[1]; //yAxisStartPointY
var difference = xAxisStartY-yAxisStartY; //gets the difference between xAxis and yAxis to make sure the points are equal distance apart.
var allPoints = []; //array to populate with points
var numberOfPoints = 4; //number of zigzags
var movement = 20; //movement left and right
for(var i=0;i<=numberOfPoints;i++){
var thisPoint = [];
if(i===0){ //push xAxisStartPoint
thisPoint.push({
x:xAxisStartX,
y:xAxisStartY
})
} else if(i===4){ //push yAxisStartPoint
thisPoint.push({
x:yAxisStartX,
y:yAxisStartY
})
} else {
thisCalcPointX;
if(i%2 > 0){ //if i is odd move left
thisCalcPointX = xAxisStartX-movement; //move point to the left
} else { //if it's even move right
thisCalcPointX = xAxisStartX+movement; //move point to the right
}
thisCalcPointY = xAxisStartY + difference/i; //move point up from xAxis start point at equal distance between xAxis and yAxis
thisPoint.push({
x: xAxisStartX,
y: thisCalcPointY
})
}
allPoints.push(thisPoint); //push this point to array of points
}
return allPoints; //return the points
}
//then pass this to create the path
var xAxisStart = [ xAxisStartX, xAxisStartY];
var yAxisStart= [ yAxisStartX, yAxisStartY];
var dataPoints = createPoints([xAxisStart, yAxisStart])
d3.select(container).data(dataPoints).enter().append('path')
.attr('x1', function(d){ return d.x1})
.attr('y1', function(d){ return d.y1})
.attr('x2', function(d){ return d.x2})
.attr('y2', function(d){ return d.y2})
.style('stroke','black');
Above code is not tested and just done on the fly, may need playing with, but the logic should work to create random points either side between both axis.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With