1

I am struggling with making this basic D3 chart responsive. I've added an event listener which calls the resize function in which I update the x and y scales and altered the width and height of the svg and call the init function with the updated values. Thanks!

          let w = () => {return window.innerWidth}
          let h = () => {return window.innerHeight}

          let svg = d3.select("body")
                      .append("svg")
                      .attr("width", w())
                      .attr("height", h())

          let data = d3.range(25).map(function() {
            return parseInt(Math.random() * 100)
          })

          const margin = () =>  {return {right: parseInt(w()*.95),
            bottom: parseInt(h()*.95)}
          }

          let x = d3.scaleLinear()
            .domain([0, d3.max(data)])
            .range([0, margin().right])

          let y = d3.scaleLinear()
            .domain([0, data.length])
            .range([0, margin().bottom])

          const init = () => {
            svg.selectAll(".bar")
              .data(data)
              .enter()
                .append("rect")
                .classed("bar", true)
                .attr("x", 0)
                .attr("y", (d, i) => y(i))
                .attr("width", (d) => {return x(d)})
                .attr("height", (d) => {return y(1) - 1})
                .attr("fill", (d) => {return "rgb(0, 0, " + d + ")"})
                .on("mouseover", function() {
                  d3.select(this).attr("fill", "red")
                })
                .on("mouseout", function(d) {
                  d3.select(this).attr("fill", "rgb(0, 0, " + d + ")")
                })

            svg.selectAll(".bar-label")
              .data(data)
              .enter()
                .append("text")
                .classed("bar-label", true)
                .attr("x", (d) => {return x(d)})
                .attr("dx",(d) => {return x(1)})
                .attr("y", (d,i) => {return y(i)})
                .attr("dy", (d,i) => {return y(1) / 1.5})
                .text((d) => {return d})
          }

          const resize = () => {
            svg.attr("width", w())
                .attr("height", h())
            x = d3.scaleLinear()
              .domain([0, d3.max(data)])
              .range([0, margin().right])

            y = d3.scaleLinear()
              .domain([0, data.length])
              .range([0, margin().bottom])

            init()
          }
          init()

          d3.select(window).on("resize", resize)
          </script>
        </html>
JGluck
  • 11
  • 2
  • I might be missing something here - it'd help if you gave a [MCVE] - but why do you want the SVG to be responsive? Why not just scale the whole image? Generally if I've needed something to be truly responsive using d3, I've done it using HTML elements rather than SVG, and used CSS to handle responsiveness. – Dan Field Mar 09 '17 at 19:09
  • I would look at - http://stackoverflow.com/questions/9400615/whats-the-best-way-to-make-a-d3-js-visualisation-layout-responsive. You could possibly avoid redrawing everything. – sparta93 Mar 09 '17 at 19:15
  • Also keep in mind - responsiveness indicates more than just saying the whole thing scales up or down... as in what you see on the image changes (e.g. at a certain scale the legend disappears) – Dan Field Mar 09 '17 at 19:15
  • Thanks Dan and sparta93. Using css does not preserve the legibility of labels. E.g if instead of numbers the labels were the names of months, I would eventually want to add a function which changes "November" to "Nov". Making the graph responsive using d3 is the first step toward that goal. – JGluck Mar 09 '17 at 19:21

0 Answers0