I’m new to Javascript, and through exploring various websites I have created a draggable points line chart. The data points are movable and the line connecting the dots is made invisible. The data points will move vertically only. I want to have grid lines with this chart. I tried but have not able to achieve it. Can someone help me with adding gridlines to this chart? I have attached the code that I have build.
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.3.0/d3.min.js"></script> <!DOCTYPE html> <style> .grid .tick { stroke: lightgrey; opacity: 0.7; } .grid path { stroke-width: 0; } .grid .tick { stroke: lightgrey; opacity: 0.7; } .grid path { stroke-width: 0; } </style> <svg width="500" height="350"></svg> <script src="https://d3js.org/d3.v4.min.js"></script> <script> var svg = d3.select("svg"), margin = {top: 20, right: 20, bottom: 30, left: 50}, width = +svg.attr("width") - margin.left - margin.right, height = +svg.attr("height") - margin.top - margin.bottom; function make_x_axis() { return d3.svg.axis() .scale(x) .orient("bottom") .ticks(5) } function make_y_axis() { return d3.svg.axis() .scale(y) .orient("left") .ticks(5) } let points = d3.range(1, 10).map(function(i) { return [i * width / 10, 50 + Math.random() * (height - 100)]; }); var x = d3.scaleLinear() .rangeRound([0, width]); var y = d3.scaleLinear() .rangeRound([height, 0]); var xAxis = d3.axisBottom(x), yAxis = d3.axisLeft(y); var line = d3.line() .x(function(d) { return x(d[0]); }) .y(function(d) { return y(d[1]); }); let drag = d3.drag() .on('start', dragstarted) .on('drag', dragged) .on('end', dragended); svg.append('rect') .attr('class', 'zoom') .attr('cursor', 'move') .attr('fill', 'none') .attr('pointer-events', 'all') .attr('width', width) .attr('height', height) .attr('transform', 'translate(' + margin.left + ',' + margin.top + ')') svg.append("g") .attr("class", "grid") .attr("transform", "translate(0," + height + ")") .call(make_x_axis() .tickSize(-height, 0, 0) .tickFormat("") ) svg.append("g") .attr("class", "grid") .call(make_y_axis() .tickSize(-width, 0, 0) .tickFormat("") ) var focus = svg.append("g") .attr("transform", "translate(" + margin.left + "," + margin.top + ")"); x.domain(d3.extent(points, function(d) { return d[0]; })); y.domain(d3.extent(points, function(d) { return d[1]; })); focus.append("path") .datum(points) .attr("fill", "none") .attr("stroke", "white") .attr("stroke-linejoin", "round") .attr("stroke-linecap", "round") .attr("stroke-width", 1.5) .attr("d", line); focus.selectAll('circle') .data(points) .enter() .append('circle') .attr('r', 5.0) .attr('cx', function(d) { return x(d[0]); }) .attr('cy', function(d) { return y(d[1]); }) .style('cursor', 'pointer') .style('fill', 'steelblue'); focus.selectAll('circle') .call(drag); focus.append('g') .attr('class', 'axis axis--x') .attr('transform', 'translate(0,' + height + ')') .call(xAxis); focus.append('g') .attr('class', 'axis axis--y') .call(yAxis); function dragstarted(d) { d3.select(this).raise().classed('active', true); } function dragged(d) { //d[0] = x.invert(d3.event.x); d[1] = y.invert(d3.event.y); d3.select(this) //.attr('cx', x(d[0])) .attr('cy', y(d[1])) focus.select('path').attr('d', line); } function dragended(d) { d3.select(this).classed('active', false); } </script>
Advertisement
Answer
The part you’re using to append the grid is from v3 of d3.js. d3v4 added d3.axisLeft()
and d3.axisBottom()
, etc. See this post.
Also, the translate
coordinates you’re using for the grid is not correct, I’ve adjusted some of the values so it fits the graph.
Here’s a working example:
<!--<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.3.0/d3.min.js"></script>--> <!DOCTYPE html> <style> .grid .tick { stroke: lightgrey; opacity: 0.7; } .grid path { stroke-width: 0; } .grid .tick { stroke: lightgrey; opacity: 0.7; } .grid path { stroke-width: 0; } </style> <svg width="500" height="350"></svg> <script src="https://d3js.org/d3.v4.min.js"></script> <script> var svg = d3.select("svg"), margin = {top: 20, right: 20, bottom: 30, left: 50}, width = +svg.attr("width") - margin.left - margin.right, height = +svg.attr("height") - margin.top - margin.bottom; function make_x_axis() { return d3.axisBottom(x) // .scale(x) // .orient("bottom") .ticks(5) } function make_y_axis() { return d3.axisLeft(y) // .scale(y) // .orient("left") .ticks(5) } let points = d3.range(1, 10).map(function(i) { return [i * width / 10, 50 + Math.random() * (height - 100)]; }); var x = d3.scaleLinear() .rangeRound([0, width]); var y = d3.scaleLinear() .rangeRound([height, 0]); var xAxis = d3.axisBottom(x), yAxis = d3.axisLeft(y); var line = d3.line() .x(function(d) { return x(d[0]); }) .y(function(d) { return y(d[1]); }); let drag = d3.drag() .on('start', dragstarted) .on('drag', dragged) .on('end', dragended); svg.append('rect') .attr('class', 'zoom') .attr('cursor', 'move') .attr('fill', 'none') .attr('pointer-events', 'all') .attr('width', width) .attr('height', height) .attr('transform', 'translate(' + margin.left + ',' + margin.top + ')') // svg.append("g") // .attr("class", "grid") // .attr('transform', 'translate(' + margin.left + ',' + margin.top + ')') // .call(make_x_axis() // .tickSize(-height, 0, 0) // .tickFormat("") // ) // // svg.append("g") // .attr("class", "grid") // .attr('transform', 'translate(' + margin.left + ',' + margin.top + ')') // // .attr("transform", "translate(0," + (height + margin.top) + ")") // .call(make_y_axis() // .tickSize(-width, 0, 0) // .tickFormat("") // ) svg.append("g") .attr("class", "grid") .attr("transform", `translate(${margin.left}, ${height + margin.top})`) .call(make_x_axis() .tickSize(-height) .tickFormat("") ) // add the Y gridlines svg.append("g") .attr("class", "grid") .attr("transform", `translate(${margin.left}, ${margin.top})`) .call(make_y_axis() .tickSize(-width) .tickFormat("") ) var focus = svg.append("g") .attr("transform", "translate(" + margin.left + "," + margin.top + ")"); x.domain(d3.extent(points, function(d) { return d[0]; })); y.domain(d3.extent(points, function(d) { return d[1]; })); focus.append("path") .datum(points) .attr("fill", "none") .attr("stroke", "white") .attr("stroke-linejoin", "round") .attr("stroke-linecap", "round") .attr("stroke-width", 1.5) .attr("d", line); focus.selectAll('circle') .data(points) .enter() .append('circle') .attr('r', 5.0) .attr('cx', function(d) { return x(d[0]); }) .attr('cy', function(d) { return y(d[1]); }) .style('cursor', 'pointer') .style('fill', 'steelblue'); focus.selectAll('circle') .call(drag); focus.append('g') .attr('class', 'axis axis--x') .attr('transform', 'translate(0,' + height + ')') .call(xAxis); focus.append('g') .attr('class', 'axis axis--y') .call(yAxis); function dragstarted(d) { d3.select(this).raise().classed('active', true); } function dragged(d) { //d[0] = x.invert(d3.event.x); d[1] = y.invert(d3.event.y); d3.select(this) //.attr('cx', x(d[0])) .attr('cy', y(d[1])) focus.select('path').attr('d', line); } function dragended(d) { d3.select(this).classed('active', false); } </script>
In case you’re wondering why the lines are “broken”, it’s because of the white best-fitting line overlapping with the grid.
Line revealed:
<!--<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.3.0/d3.min.js"></script>--> <!DOCTYPE html> <style> .grid .tick { stroke: lightgrey; opacity: 0.7; } .grid path { stroke-width: 0; } .grid .tick { stroke: lightgrey; opacity: 0.7; } .grid path { stroke-width: 0; } </style> <svg width="500" height="350"></svg> <script src="https://d3js.org/d3.v4.min.js"></script> <script> var svg = d3.select("svg"), margin = {top: 20, right: 20, bottom: 30, left: 50}, width = +svg.attr("width") - margin.left - margin.right, height = +svg.attr("height") - margin.top - margin.bottom; function make_x_axis() { return d3.axisBottom(x) // .scale(x) // .orient("bottom") .ticks(5) } function make_y_axis() { return d3.axisLeft(y) // .scale(y) // .orient("left") .ticks(5) } let points = d3.range(1, 10).map(function(i) { return [i * width / 10, 50 + Math.random() * (height - 100)]; }); var x = d3.scaleLinear() .rangeRound([0, width]); var y = d3.scaleLinear() .rangeRound([height, 0]); var xAxis = d3.axisBottom(x), yAxis = d3.axisLeft(y); var line = d3.line() .x(function(d) { return x(d[0]); }) .y(function(d) { return y(d[1]); }); let drag = d3.drag() .on('start', dragstarted) .on('drag', dragged) .on('end', dragended); svg.append('rect') .attr('class', 'zoom') .attr('cursor', 'move') .attr('fill', 'none') .attr('pointer-events', 'all') .attr('width', width) .attr('height', height) .attr('transform', 'translate(' + margin.left + ',' + margin.top + ')') // svg.append("g") // .attr("class", "grid") // .attr('transform', 'translate(' + margin.left + ',' + margin.top + ')') // .call(make_x_axis() // .tickSize(-height, 0, 0) // .tickFormat("") // ) // // svg.append("g") // .attr("class", "grid") // .attr('transform', 'translate(' + margin.left + ',' + margin.top + ')') // // .attr("transform", "translate(0," + (height + margin.top) + ")") // .call(make_y_axis() // .tickSize(-width, 0, 0) // .tickFormat("") // ) svg.append("g") .attr("class", "grid") .attr("transform", `translate(${margin.left}, ${height + margin.top})`) .call(make_x_axis() .tickSize(-height) .tickFormat("") ) // add the Y gridlines svg.append("g") .attr("class", "grid") .attr("transform", `translate(${margin.left}, ${margin.top})`) .call(make_y_axis() .tickSize(-width) .tickFormat("") ) var focus = svg.append("g") .attr("transform", "translate(" + margin.left + "," + margin.top + ")"); x.domain(d3.extent(points, function(d) { return d[0]; })); y.domain(d3.extent(points, function(d) { return d[1]; })); focus.append("path") .datum(points) .attr("fill", "none") .attr("stroke", "black") // modified .attr("stroke-linejoin", "round") .attr("stroke-linecap", "round") .attr("stroke-width", 1.5) .attr("d", line); focus.selectAll('circle') .data(points) .enter() .append('circle') .attr('r', 5.0) .attr('cx', function(d) { return x(d[0]); }) .attr('cy', function(d) { return y(d[1]); }) .style('cursor', 'pointer') .style('fill', 'steelblue'); focus.selectAll('circle') .call(drag); focus.append('g') .attr('class', 'axis axis--x') .attr('transform', 'translate(0,' + height + ')') .call(xAxis); focus.append('g') .attr('class', 'axis axis--y') .call(yAxis); function dragstarted(d) { d3.select(this).raise().classed('active', true); } function dragged(d) { //d[0] = x.invert(d3.event.x); d[1] = y.invert(d3.event.y); d3.select(this) //.attr('cx', x(d[0])) .attr('cy', y(d[1])) focus.select('path').attr('d', line); } function dragended(d) { d3.select(this).classed('active', false); } </script>