D3.js多系列时间轴逐一绘制

时间:2016-08-23 07:07:07

标签: javascript d3.js

这是jsfiddle https://jsfiddle.net/zdmnus3m/

我可以绘制/绘制多系列时间轴。这是我的代码库

var city = svg.selectAll(".city")
          .data(citiesdata)
          .enter().append("g")
          .attr("class", "city");

        city.append("path")
          .attr("class", "line")
          .attr("d", function(d) {
            return line(d.values);
          })
          .style("stroke", function(d) {
            return color(d.name);
          });

        city.append("text")
          .datum(function(d) {
            return {
              name: d.name,
              value: d.values[d.values.length - 1]
            };
          })
          .attr("transform", function(d) {
            return "translate(" + x(d.value.date) + "," + y(d.value.temperature) + ")";
          })
          .attr("x", 3)
          .attr("dy", ".35em")
          .text(function(d) {
            return d.name;
          });       

所以这段代码一次性绘制所有时间轴,我想一个接一个地添加动画和绘图。这怎么可能。如果带有transition的{​​{1}}属性可以使用。我不确定。任何帮助表示赞赏。

1 个答案:

答案 0 :(得分:0)

首先,您对getTotalLength的计算是错误的,您仅在计算第一条路径的长度。应该是:

.attr("stroke-dashoffset", function(){
    return this.getTotalLength();
})

已修复,解决方案是使用节点索引的简单delay

.delay(function(_,i){
    return 2000 * i;
})

这是您的代码,其中有两项更改:

 var myData = "date	New York	San Francisco	Austin	Bangalore\n\
20111001	63.4	62.7	72.2	32.6\n\
20111002	58.0	59.9	67.7	43.9\n\
20111003	53.3	59.1	69.4	55.0\n\
20111004	55.7	58.8	68.0	54.0\n\
20111005	64.2	58.7	72.4	23.7\n\
20111006	58.8	57.0	77.0	56.0\n\
20111007	57.9	56.7	82.3	98.0\n\
20111008	61.8	56.8	78.9	45.0\n\
20111009	69.3	56.7	68.8	65.0\n\
20111010	71.2	60.1	68.7	65.0\n\
20111011	68.7	61.1	70.3	45.0\n\
20111012	61.8	61.5	75.3	34.5\n\
20111013	63.0	64.3	76.6	56.9\n\
20111014	66.9	67.1	66.6	12.0\n\
20111015	61.7	64.6	68.0	87.0\n\
20111016	61.8	61.6	70.6	77.3\n\
20111017	62.8	61.1	71.1	34.8\n\
20111018	60.8	59.2	70.0	56.7\n\
20111019	62.1	58.9	61.6	29.9\n\
20111020	65.1	57.2	57.4	34.9\n\
20111021	55.6	56.4	64.3	56.0\n\
20111022	54.4	60.7	72.4	66.0\n";

 var margin = {
     top: 20,
     right: 80,
     bottom: 30,
     left: 50
   },
   width = 800 - margin.left - margin.right,
   height = 500 - margin.top - margin.bottom;

 var parseDate = d3.time.format("%Y%m%d").parse;

 var x = d3.time.scale()
   .range([0, width]);

 var y = d3.scale.linear()
   .range([height, 0]);

 var color = d3.scale.category10();

 var xAxis = d3.svg.axis()
   .scale(x)
   .orient("bottom");

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

 var line = d3.svg.line()
   .interpolate("basis")
   .x(function(d) {
     return x(d.date);
   })
   .y(function(d) {
     return y(d.temperature);
   });



 var data = d3.tsv.parse(myData);

 color.domain(d3.keys(data[0]).filter(function(key) {
   return key !== "date";
 }));

 data.forEach(function(d) {
   d.date = parseDate(d.date);
 });

 var cities = color.domain().map(function(name) {
   return {
     name: name,
     values: data.map(function(d) {
       return {
         date: d.date,
         temperature: +d[name]
       };
     })
   };
 });

 var newCities = cities

 var legend = d3.select("#legend").append("svg")
   .attr("width", width + margin.left + margin.right)
   .attr("height", height + margin.top + margin.bottom)
   .selectAll('g')
   .data(newCities)
   .enter()
   .append('g')
   .attr('class', 'legend');

 legend.append('rect')
   .attr('x', width - 20)
   .attr('y', function(d, i) {
     return i * 20;
   })
   .attr('width', 10)
   .attr('height', 10)
   .style('fill', function(d) {
     return color(d.name);
   });

 legend.append('text')
   .attr("id", function(d) {
     return d.name.replace(/[^a-z\d\s]+/gi, "").replace(/ /g, '');
   })
   .attr('x', width - 8)
   .attr('y', function(d, i) {
     return (i * 20) + 9;
   })
   .text(function(d) {
     return d.name;
   })
   .attr("fill", "black")
   .style("cursor", "pointer")
   .on("click", function(d) {
     drawBoxes(this.id);
   });



 var svg = d3.select("#mysvg").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 + ")");
 plottimelines(svg, cities)

 function plottimelines(svg, citiesdata) {



   x.domain(d3.extent(data, function(d) {
     return d.date;
   }));

   y.domain([
     d3.min(citiesdata, function(c) {
       return d3.min(c.values, function(v) {
         return v.temperature;
       });
     }),
     d3.max(citiesdata, function(c) {
       return d3.max(c.values, function(v) {
         return v.temperature;
       });
     })
   ]);

   //for(var i=0;i<citiesdata.length;i++){
   var city = svg.selectAll(".city")
     .data(citiesdata)
     .enter().append("g")
     .attr("class", "city");

   var path = city.append("path")
     .attr("class", "line")
     .attr("d", function(d) {
       return line(d.values);
     })
     .style("stroke", function(d) {
       return color(d.name);
     });

   path.attr("stroke-dasharray", tweenDash)
     .attr("stroke-dashoffset", function() {
       return this.getTotalLength();
     })
     .transition()
     .duration(2000)
     .delay(function(_, i) {
       return 2000 * i;
     })
     .ease("linear")
     .attr("stroke-dashoffset", 0);

   city.append("text")
     .datum(function(d) {
       return {
         name: d.name,
         value: d.values[d.values.length - 1]
       };
     })
     .attr("transform", function(d) {
       return "translate(" + x(d.value.date) + "," + y(d.value.temperature) + ")";
     })
     .attr("x", 3)
     .attr("dy", ".35em")
     .text(function(d) {
       return d.name;
     });
   city.append("g")
     .attr("class", "x axis")
     .attr("transform", "translate(0," + height + ")")
     .call(xAxis);

   city.append("g")
     .attr("class", "y axis")
     .call(yAxis)
     .append("text")
     .attr("transform", "rotate(-90)")
     .attr("y", 6)
     .attr("dy", ".71em")
     .style("text-anchor", "end")
     .text("Temperature (ºF)");

   //}
   function tweenDash() {
     var l = this.getTotalLength()
     return (l + " " + l);
   }


   var mouseG = svg.append("g")
     .attr("class", "mouse-over-effects");

   mouseG.append("path") // this is the black vertical line to follow mouse
     .attr("class", "mouse-line")
     .style("stroke", "black")
     .style("stroke-width", "1px")
     .style("opacity", "0");

   var lines = document.getElementsByClassName('line');

   var mousePerLine = mouseG.selectAll('.mouse-per-line')
     .data(citiesdata)
     .enter()
     .append("g")
     .attr("class", "mouse-per-line");

   mousePerLine.append("circle")
     .attr("r", 7)
     .style("stroke", function(d) {
       return color(d.name);
     })
     .style("fill", "none")
     .style("stroke-width", "1px")
     .style("opacity", "0");

   mousePerLine.append("text")
     .attr("transform", "translate(10,3)");

   mouseG.append('svg:rect') // append a rect to catch mouse movements on canvas
     .attr('width', width) // can't catch mouse events on a g element
     .attr('height', height)
     .attr('fill', 'none')
     .attr('pointer-events', 'all')
     .on('mouseout', function() { // on mouse out hide line, circles and text
       d3.select(".mouse-line")
         .style("opacity", "0");
       d3.selectAll(".mouse-per-line circle")
         .style("opacity", "0");
       d3.selectAll(".mouse-per-line text")
         .style("opacity", "0");
     })
     .on('mouseover', function() { // on mouse in show line, circles and text
       d3.select(".mouse-line")
         .style("opacity", "1");
       d3.selectAll(".mouse-per-line circle")
         .style("opacity", "1");
       d3.selectAll(".mouse-per-line text")
         .style("opacity", "1");
     })
     .on('mousemove', function() { // mouse moving over canvas
       var mouse = d3.mouse(this);
       d3.select(".mouse-line")
         .attr("d", function() {
           var d = "M" + mouse[0] + "," + height;
           d += " " + mouse[0] + "," + 0;
           return d;
         });

       d3.selectAll(".mouse-per-line")
         .attr("transform", function(d, i) {
           console.log(width / mouse[0])
           var xDate = x.invert(mouse[0]),
             bisect = d3.bisector(function(d) {
               return d.date;
             }).right;
           idx = bisect(d.values, xDate);

           var beginning = 0,
             end = lines[i].getTotalLength(),
             target = null;

           while (true) {
             target = Math.floor((beginning + end) / 2);
             pos = lines[i].getPointAtLength(target);
             if ((target === end || target === beginning) && pos.x !== mouse[0]) {
               break;
             }
             if (pos.x > mouse[0]) end = target;
             else if (pos.x < mouse[0]) beginning = target;
             else break; //position found
           }

           d3.select(this).select('text')
             .text(y.invert(pos.y).toFixed(2));

           return "translate(" + mouse[0] + "," + pos.y + ")";
         });
     });

 }



 function drawBoxes(id) {



   var color_ = d3.select('#' + id).attr("fill");
   console.log(color_)
   if (color_ == 'black') {
     d3.select('#' + id).attr("fill", "#FFFAFA");
   } else {
     d3.select('#' + id).attr("fill", "black");
   }

   var results = newCities.filter(function(d) {
     var colorText = d3.select('#' + d.name.replace(/[^a-z\d\s]+/gi, "").replace(/ /g, '')).attr("fill");
     if (colorText == 'black') {
       return {
         name: d.name,
         values: data.map(function(d) {
           return {
             date: d.date,
             temperature: +d[name]
           };
         })
       };
     }
   });
   var myNode = document.getElementById("mysvg");
   while (myNode.firstChild) {
     myNode.removeChild(myNode.firstChild);
   }
   //console.log(results)
   //console.log([results[0]])
   var svg = d3.select("#mysvg").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 + ")");
   //for(var i=0;i<results.length;i++){
   plottimelines(svg, results)
   //}

 }
body {
  font: 10px sans-serif;
}

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

.x.axis path {
  display: none;
}

.line {
  fill: none;
  stroke: steelblue;
  stroke-width: 1.5px;
}
<script data-require="d3@3.5.3" data-semver="3.5.3" src="//cdnjs.cloudflare.com/ajax/libs/d3/3.5.3/d3.js"></script>
<div id="mysvg"></div>
<div id="legend"></div>