简体   繁体   English

折线图轴缩放

[英]Line chart axis zoom

I've got some problems with my d3 visualization. d3可视化出现一些问题。 I'm trying to do a line chart that shows a development over 15 years. 我正在尝试制作折线图,以显示15年来的发展。

First problem is that the x-axis does't scale depending on the zoom. 第一个问题是x轴不会根据缩放比例缩放。 I've used this to get started: http://bl.ocks.org/mbostock/4dc8736fb1ce9799c6d6 But I don't know why my axis doesn't zoom. 我已经开始使用它了: http : //bl.ocks.org/mbostock/4dc8736fb1ce9799c6d6但是我不知道为什么我的轴不能缩放。

Second, the axis labeling is wrong, it should be the week and the year (eg01-2016) 其次,轴标签错误,应该是星期和年份(例如,01-2016)

And the last: What opportunities do I have, if there is some data missing, for example the data for the year 2013? 最后一点:如果缺少某些数据(例如2013年的数据),我有什么机会? Can I have a break in the chart, so that there is just a white space for this year? 我可以在图表中休息一下,以便今年只有空白吗?

Here is the HTML 这是HTML

<!doctype html>
<html>
  <head>  
    <link rel="stylesheet" href="main.css">
    <script src="//d3js.org/d3.v3.min.js"></script>
    <title>Test Tool</title> 
  </head> 

  <body>  
    <!--MAIN-->
    <main>

    <!--LINE CHART -->
    <script>
    // Set the dimensions of the canvas / graph
    var margin = {top: 10, right: 20, bottom: 30, left: 50},
        width = 1000 - margin.left - margin.right,
        height = 570 - margin.top - margin.bottom;

    // Set the ranges
    var x = d3.time.scale().domain([-width / 2, width / 2])
        .range([0, width]);
    var y = d3.scale.linear().domain([-height / 2, height / 2])
        .range([height, 0]);


    // Define the axes
    var xAxis = d3.svg.axis().scale(x)
        .orient("bottom").ticks(10);

    var yAxis = d3.svg.axis().scale(y)
        .orient("left").ticks(5);

    var zoom = d3.behavior.zoom()
        .x(x)
        .y(y)
        .scaleExtent([1, 10])
        .on("zoom", zoomed);

    var drag = d3.behavior.drag()
        .origin(function(d) { return d; })
        .on("dragstart", dragstarted)
        .on("drag", dragged)
        .on("dragend", dragended);

    var area = d3.svg.area()
        .x(function(d) { return x(d.meldewoche); })
        .y0(height)
        .y1(function(d) { return y(d.faelle); })
        .interpolate("basis");

    var areaflip = d3.svg.area()
        .x(function(d) { return x(d.meldewoche); })
        .y0(height)
        .y1(function(d) { return y(-d.faelle); })
        .interpolate("basis");

    // Define the line
    var valueline = d3.svg.line()
        .x(function(d) { return x(d.meldewoche); })
        .y(function(d) { return y(d.faelle); })
        .interpolate("basis");

    var valuelineflip = d3.svg.line()
        .x(function(d) { return x(d.meldewoche); })
        .y(function(d) { return y(-d.faelle); })
        .interpolate("basis");

    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 + ")")
            .call(zoom); 

    var container = svg.append("g");

    var rect = svg.append("rect")
        .attr("width", width)
        .attr("height", height)
        .style("fill", "none")
        .style("pointer-events", "all");

    // Add the X Axis
    svg.append("g")
            .attr("class", "x axis")
            .attr("transform", "translate(0," + height + ")")
            .call(xAxis);

    // Add the Y Axis
    svg.append("g")
            .attr("class", "y axis")
            .call(yAxis);

    // Get the data
    d3.csv("data-hanta-gesamt.csv", function(error, data) {
        data.forEach(function(d) {
            // Parse the date / time
            var parseDate = d3.time.format("%W-%Y").parse;
            d.meldewoche = parseDate(d.meldewoche);
            d.faelle = +d.faelle; 
        });

    // Scale the range of the data
    x.domain(d3.extent(data, function(d) { return d.meldewoche; }));
    y.domain([0, d3.max(data, function(d) { return d.faelle+550; })]);

    // Add the valueline path.
    container.append("path")
            .attr("class", "line")
            .attr("d", valueline(data))
            .attr("transform", "translate(0,-265)");
    container.append("path")
            .attr("class", "lineflip")
            .attr("d", valuelineflip(data))
            .attr("transform", "translate(0,-265)");

    container.append("path")
            .datum(data)
            .attr("class", "area")
            .attr("d", area)
            .attr("transform", "translate(0,-265)"); 
    container.append("path")
            .datum(data)
            .attr("class", "areaflip")
            .attr("d", areaflip)
            .attr("transform", "translate(0,-265)");

    });


    //ZOOM
    function zoomed() {
        container.select(".x axis").call(xAxis);
        container.select(".y axis").call(yAxis); 
        //svg.selectAll('.line').attr('d', line)  
      container.attr("transform", "translate(" + d3.event.translate[0] + ",0)scale(" + d3.event.scale + ",1)");

    }

    function dragstarted(d) {
      d3.event.sourceEvent.stopPropagation();
      d3.select(this).classed("dragging", true);
    }

    function dragged(d) {
      d3.select(this)
          .attr("cx", d.x = d3.event.x)
          .attr("cy", d.y = d3.event.y);
    }

    function dragended(d) {
      d3.select(this).classed("dragging", false);
    }


    </script>
    </main>     
  </body>
</html>

And the CSS: 和CSS:

     body {
        background: #E1E2DD;
        color: #333;
        font: 1em/1em "Helvetica Neue";
      }

      #main {
        float: left;
        padding: 3em;
        width: 65%;
      }
      #footer {
        padding: 1em;
        text-align: right;
        width:65%; 
      }

.axis path,
.axis line {
    fill: none;
    stroke: #000;
    stroke-width: 1;
    shape-rendering: crispEdges;
}       

.x.axis path {
    display: none;
}

.line {
        fill: none;
        stroke: steelblue;
        stroke-width: 1.5px;
      }

.lineflip {
        fill: none;
        stroke: steelblue;
        stroke-width: 1.5px;
}

.area {
    fill: lightsteelblue;
      stroke-width: 0;
      fill-opacity: .67;
}

.areaflip {
    fill: lightsteelblue;
      stroke-width: 0;
      fill-opacity: .67;
}

The csv looks like this: csv看起来像这样:

meldewoche,faelle
01-2001,2
03-2001,1
04-2001,2
05-2001,2
07-2001,1
08-2001,6
09-2001,1
...

You just need to small changes to fix the issues you mentioned. 您只需要进行少量更改即可解决您提到的问题。

  1. Issue 1: the x-axis doesn't scale in response to the zoom. 问题1:x轴无法响应缩放。 The problem you're having comes from how you are updating the x- and y-axes in zoomed . 您遇到的问题来自于您是如何更新的x和y轴zoomed In particular, your current code tries to select the axes from container : 特别是,您当前的代码尝试从container选择轴:

     container.select(".x axis").call(xAxis); container.select(".y axis").call(yAxis); 

    However, the axes are not children of container . 但是,轴不是container子代。 Furthermore, you replaced the . 此外,您还替换了. required to select the axes by the class "axis" with a space. 需要在带有空格的“轴”类中选择轴。 If instead you select the axes as children of the svg and setting the class selector properly, then your zoom behavior will work: 相反,如果您选择轴作为svg子代并正确设置类选择器,则缩放行为将起作用:

     svg.select(".x.axis").call(xAxis); svg.select(".y.axis").call(yAxis); 
  2. Issue 2: The x-axis labeling is wrong. 问题2:x轴标签错误。 This problem stems from the fact that you are adding the x-axis before loading your data. 此问题源于您加载数据之前添加x轴的事实。 Thus, the domain of the x-axis hasn't been set using the dates of your data. 因此,尚未使用数据日期设置x轴的域。

    The solution to this problem is to move all of the code that relies on the x-axis into your d3.csv . 解决此问题的方法是将所有依赖x轴的代码移到d3.csv This way, when you add the axis or even when you zoom, the domain of the scale x for the x-axis has already been set properly. 这样,当您添加轴或什至缩放时,已经正确设置了x轴的比例x的域。 Here's the updated Javascript that's working for me. 这是为我工作的更新的Javascript。

// Set the dimensions of the canvas / graph var margin = { top: 10, right: 20, bottom: 30, left: 50 }, width = 1000 - margin.left - margin.right, height = 570 - margin.top - margin.bottom; //设置画布/图形的尺寸var margin = {顶部:10,右侧:20,底部:30,左侧:50},宽度= 1000-margin.left-margin.right,高度= 570-margin.top -margin.bottom;

// Set the ranges
var x = d3.time.scale().domain([-width / 2, width / 2])
  .range([0, width]);
var y = d3.scale.linear().domain([-height / 2, height / 2])
  .range([height, 0]);

// Define the axes
var xAxis = d3.svg.axis().scale(x)
  .orient("bottom").ticks(10);

var yAxis = d3.svg.axis().scale(y)
  .orient("left").ticks(5);

// Get the data
d3.csv("data-hanta-gesamt.csv", function(error, data) {
  data.forEach(function(d) {
    // Parse the date / time
    var parseDate = d3.time.format("%W-%Y").parse;
    d.meldewoche = parseDate(d.meldewoche);
    d.faelle = +d.faelle;
  });


  var drag = d3.behavior.drag()
    .origin(function(d) {
      return d;
    })
    .on("dragstart", dragstarted)
    .on("drag", dragged)
    .on("dragend", dragended);

  var area = d3.svg.area()
    .x(function(d) {
      return x(d.meldewoche);
    })
    .y0(height)
    .y1(function(d) {
      return y(d.faelle);
    })
    .interpolate("basis");

  var areaflip = d3.svg.area()
    .x(function(d) {
      return x(d.meldewoche);
    })
    .y0(height)
    .y1(function(d) {
      return y(-d.faelle);
    })
    .interpolate("basis");

  // Define the line
  var valueline = d3.svg.line()
    .x(function(d) {
      return x(d.meldewoche);
    })
    .y(function(d) {
      return y(d.faelle);
    })
    .interpolate("basis");

  var valuelineflip = d3.svg.line()
    .x(function(d) {
      return x(d.meldewoche);
    })
    .y(function(d) {
      return y(-d.faelle);
    })
    .interpolate("basis");

  // Scale the range of the data
  x.domain(d3.extent(data, function(d) {
    return d.meldewoche;
  }));
  y.domain([0, d3.max(data, function(d) {
    return d.faelle + 550;
  })]);

  var zoom = d3.behavior.zoom()
    .x(x)
    .y(y)
    .scaleExtent([1, 10])
    .on("zoom", zoomed);

  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 + ")")
    .call(zoom);

  var container = svg.append("g");

  var rect = svg.append("rect")
    .attr("width", width)
    .attr("height", height)
    .style("fill", "none")
    .style("pointer-events", "all");

  // Add the Y Axis
  svg.append("g")
    .attr("class", "y axis")
    .call(yAxis);

  // Add the X Axis
  svg.append("g")
    .attr("class", "x axis")
    .attr("transform", "translate(0," + height + ")")
    .call(xAxis);

  // Add the valueline path.
  container.append("path")
    .attr("class", "line")
    .attr("d", valueline(data))
    .attr("transform", "translate(0,-265)");
  container.append("path")
    .attr("class", "lineflip")
    .attr("d", valuelineflip(data))
    .attr("transform", "translate(0,-265)");

  container.append("path")
    .datum(data)
    .attr("class", "area")
    .attr("d", area)
    .attr("transform", "translate(0,-265)");
  container.append("path")
    .datum(data)
    .attr("class", "areaflip")
    .attr("d", areaflip)
    .attr("transform", "translate(0,-265)");


  //ZOOM
  function zoomed() {
    svg.select(".x.axis").call(xAxis);
    svg.select(".y.axis").call(yAxis);
    //svg.selectAll('.line').attr('d', line)  
    container.attr("transform", "translate(" + d3.event.translate[0] + ",0)scale(" + d3.event.scale + ",1)");

  }

  function dragstarted(d) {
    d3.event.sourceEvent.stopPropagation();
    d3.select(this).classed("dragging", true);
  }

  function dragged(d) {
    d3.select(this)
      .attr("cx", d.x = d3.event.x)
      .attr("cy", d.y = d3.event.y);
  }

  function dragended(d) {
    d3.select(this).classed("dragging", false);
  }
});

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM