[D3] Make D3 v4 Charts Responsive with the viewBox attribute
Making SVGs responsive is unfortunately not as simple as adding some media queries. This lesson introduces the viewBox
attribute, which is used to control how SVGs scale. We’ll also examine a reusable function that can be used to make nearly any visualization responsive.
var margin = { top: 10, right: 20, bottom: 30, left: 30 }; var width = 400 - margin.left - margin.right; var height = 600 - margin.top - margin.bottom; var svg = d3.select('.chart') .append('svg') .attr('width', width + margin.left + margin.right) .attr('height', height + margin.top + margin.bottom) .call(responsivefy) .append('g') .attr('transform', 'translate(' + margin.left + ', ' + margin.top + ')'); svg.append('rect') .attr('width', width) .attr('height', height) .style('fill', 'lightblue') .style('stroke', 'green'); var yScale = d3.scaleLinear() .domain([0, 100]) .range([height, 0]); var yAxis = d3.axisLeft(yScale); svg.call(yAxis); var xScale = d3.scaleTime() .domain([new Date(2016, 0, 1, 6), new Date(2016, 0, 1, 9)]) .range([0, width]); var xAxis = d3.axisBottom(xScale) .ticks(5) .tickSize(10) .tickPadding(5); svg .append('g') .attr('transform', `translate(0, ${height})`) .call(xAxis); function responsivefy(svg) { // get container + svg aspect ratio var container = d3.select(svg.node().parentNode), width = parseInt(svg.style("width")), height = parseInt(svg.style("height")), aspect = width / height; // add viewBox and preserveAspectRatio properties, // and call resize so that svg resizes on inital page load svg.attr("viewBox", "0 0 " + width + " " + height) .attr("preserveAspectRatio", "xMinYMid") .call(resize); // to register multiple listeners for same event type, // you need to add namespace, i.e., 'click.foo' // necessary if you call invoke this function for multiple svgs // api docs: https://github.com/mbostock/d3/wiki/Selections#on d3.select(window).on("resize." + container.attr("id"), resize); // get width of container and resize svg to fit it function resize() { var targetWidth = parseInt(container.style("width")); svg.attr("width", targetWidth); svg.attr("height", Math.round(targetWidth / aspect)); } }