为什么图例在缩放时会与 d3.js 折线图合并?

问题描述 投票:0回答:1

我正在尝试向名为 d3.js 的示例添加一个图例 d3.js 中放大的折线图

1°)我添加了脚本:

// Add legend rectangle
line.append('rect')
          .attr('x', width - 80)
          .attr('y', 90)
          .attr('width', 10)
          .attr('height', 10)
          .style('fill', "steelblue");

// Add legend text 
line.append("text")
          .attr('x', width - 65)
          .attr('y', 100)
          .text('Blue line');

2°)我减少了现有代码中的 x 轴以将图例和图表分开:

var x = d3.scaleTime()
      .domain(d3.extent(data, function(d) { return d.date; }))
      .range([ 0, width - 100  ]);

不幸的是,当我缩放时,图例与图表合并了!怎么解决这个问题?

After zooming

javascript d3.js charts legend zoom-sdk
1个回答
0
投票

您下面的示例遵循

d3
中常用的编码约定,将图表的“绘图区域”围绕一系列边距分开。

// set the dimensions and margins of the graph
var margin = { top: 10, right: 100, bottom: 30, left: 60 },
  width = 460 - margin.left - margin.right,
  height = 400 - margin.top - margin.bottom;

// append the svg object to the body of the page
var svg = d3
  .select('#my_dataviz')
  .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 + ')');

我不会尝试按照您的方式调整 x 轴比例,而是增加右边距并将图例移动到那里。

这是一个例子:

<!DOCTYPE html>

<html>
  <head>
    <link rel="stylesheet" href="lib/style.css" />
    <script src="lib/script.js"></script>
  </head>

  <body>
    <!-- Load d3.js -->
    <script src="https://d3js.org/d3.v4.js"></script>

    <!-- Create a div where the graph will take place -->
    <div id="my_dataviz"></div>

    <script>
      // set the dimensions and margins of the graph
      var margin = { top: 10, right: 100, bottom: 30, left: 60 },
        width = 460 - margin.left - margin.right,
        height = 400 - margin.top - margin.bottom;

      // append the svg object to the body of the page
      var svg = d3
        .select('#my_dataviz')
        .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 + ')');

      //Read the data
      d3.csv(
        'https://raw.githubusercontent.com/holtzy/data_to_viz/master/Example_dataset/3_TwoNumOrdered_comma.csv',

        // When reading the csv, I must format variables:
        function (d) {
          return { date: d3.timeParse('%Y-%m-%d')(d.date), value: d.value };
        },

        // Now I can use this dataset:
        function (data) {
          // Add X axis --> it is a date format
          var x = d3
            .scaleTime()
            .domain(
              d3.extent(data, function (d) {
                return d.date;
              })
            )
            .range([0, width]);
          xAxis = svg
            .append('g')
            .attr('transform', 'translate(0,' + height + ')')
            .call(d3.axisBottom(x));

          // Add Y axis
          var y = d3
            .scaleLinear()
            .domain([
              0,
              d3.max(data, function (d) {
                return +d.value;
              }),
            ])
            .range([height, 0]);
          yAxis = svg.append('g').call(d3.axisLeft(y));

          // Add a clipPath: everything out of this area won't be drawn.
          var clip = svg
            .append('defs')
            .append('svg:clipPath')
            .attr('id', 'clip')
            .append('svg:rect')
            .attr('width', width)
            .attr('height', height)
            .attr('x', 0)
            .attr('y', 0);

          // Add brushing
          var brush = d3
            .brushX() // Add the brush feature using the d3.brush function
            .extent([
              [0, 0],
              [width, height],
            ]) // initialise the brush area: start at 0,0 and finishes at width,height: it means I select the whole graph area
            .on('end', updateChart); // Each time the brush selection changes, trigger the 'updateChart' function

          // Create the line variable: where both the line and the brush take place
          var line = svg.append('g').attr('clip-path', 'url(#clip)');

          // Add the line
          line
            .append('path')
            .datum(data)
            .attr('class', 'line') // I add the class line to be able to modify this line later on.
            .attr('fill', 'none')
            .attr('stroke', 'steelblue')
            .attr('stroke-width', 1.5)
            .attr(
              'd',
              d3
                .line()
                .x(function (d) {
                  return x(d.date);
                })
                .y(function (d) {
                  return y(d.value);
                })
            );

          // Add the brushing
          line.append('g').attr('class', 'brush').call(brush);

          // A function that set idleTimeOut to null
          var idleTimeout;
          function idled() {
            idleTimeout = null;
          }

          // add a legend
          let legend = svg.append('g')
            .attr('transform', 'translate(' + (width+10) + ', 10)')
            .attr('class', 'legend');

          legend.append('rect')
            .attr('width', 10)
            .attr('height', 10)
            .attr('fill', 'steelblue');

          legend.append('text')
            .attr('x', 12)
            .attr('y', 10)
            .text('My Line!');

          // A function that update the chart for given boundaries
          function updateChart() {
            // What are the selected boundaries?
            extent = d3.event.selection;

            // If no selection, back to initial coordinate. Otherwise, update X axis domain
            if (!extent) {
              if (!idleTimeout) return (idleTimeout = setTimeout(idled, 350)); // This allows to wait a little bit
              x.domain([4, 8]);
            } else {
              x.domain([x.invert(extent[0]), x.invert(extent[1])]);
              line.select('.brush').call(brush.move, null); // This remove the grey brush area as soon as the selection has been done
            }

            // Update axis and line position
            xAxis.transition().duration(1000).call(d3.axisBottom(x));
            line
              .select('.line')
              .transition()
              .duration(1000)
              .attr(
                'd',
                d3
                  .line()
                  .x(function (d) {
                    return x(d.date);
                  })
                  .y(function (d) {
                    return y(d.value);
                  })
              );
          }

          // If user double click, reinitialize the chart
          svg.on('dblclick', function () {
            x.domain(
              d3.extent(data, function (d) {
                return d.date;
              })
            );
            xAxis.transition().call(d3.axisBottom(x));
            line
              .select('.line')
              .transition()
              .attr(
                'd',
                d3
                  .line()
                  .x(function (d) {
                    return x(d.date);
                  })
                  .y(function (d) {
                    return y(d.value);
                  })
              );
          });
        }
      );
    </script>
  </body>
</html>

© www.soinside.com 2019 - 2024. All rights reserved.