javascript - d3.js 按索引在特定点向折线图添加垂直线

标签 javascript d3.js dc.js

在三个相似的折线图(相同的数据集)之间画一条垂直线有些困难。

Var testdate1 包含一个日期,可在图表 (lc1.on(renderlet) 函数顶部) 的索引处找到pos 4(折线图上的第 4 个“circle.dot”)。

如何在图表的那个位置添加一条垂直线? (我希望在所有三个折线图的相同位置添加垂直线,但我希望所有三个都采用相同的过程)。

此外,出于某种原因,我无法将那个位置的圆圈设置为红点或绿点,尽管它在 this SO answer by davcs86 中有效。 -- 但在他的示例中,我们使用 x 轴(日期)定位点,并且此代码使用 alldotsN 集合中的索引号 -- 也看不出我在这里做错了什么。

jsFiddle to experiment with

var chartHeight = 250;
var chartWidth = 500;
var myCSV = [	
  {"shift":"1","date":"01/01/2016/08/00/00/+0500","car":"178","truck":"125","bike":"317","moto":"237"},
  {"shift":"2","date":"01/01/2016/17/00/00/+0500","car":"125","truck":"189","bike":"125","moto":"273"},
  {"shift":"3","date":"02/01/2016/08/00/00/-0500","car":"140","truck":"219","bike":"328","moto":"1252"},
  {"shift":"4","date":"02/01/2016/17/00/00/+0500","car":"222","truck":"290","bike":"432","moto":"378"},
  {"shift":"5","date":"03/01/2016/08/00/00/+0500","car":"200","truck":"250","bike":"420","moto":"319"},
  {"shift":"6","date":"03/01/2016/17/00/00/+0500","car":"230","truck":"220","bike":"310","moto":"413"},
  {"shift":"7","date":"04/01/2016/08/00/00/+0500","car":"155","truck":"177","bike":"377","moto":"180"},
  {"shift":"8","date":"04/01/2016/17/00/00/+0500","car":"179","truck":"203","bike":"405","moto":"222"},
  {"shift":"9","date":"05/01/2016/08/00/00/+0500","car":"208","truck":"185","bike":"360","moto":"195"},
  {"shift":"10","date":"05/01/2016/17/00/00/+0500","car":"150","truck":"290","bike":"315","moto":"280"},
  {"shift":"11","date":"06/01/2016/08/00/00/+0500","car":"200","truck":"220","bike":"350","moto":"205"},
  {"shift":"12","date":"06/01/2016/17/00/00/+0500","car":"230","truck":"170","bike":"390","moto":"400"}
];
var testdate1 = +new Date('Sun Jan 03 2016 08:00:00 GMT-0500 (Eastern Standard Time)');
lc1 = dc.lineChart("#line1");
lc2 = dc.lineChart("#line2");
lc3 = dc.lineChart("#line3");

var dateFormat = d3.time.format("%d/%m/%Y/%H/%M/%S/%Z");
myCSV.forEach(function (d) {
	d.date = dateFormat.parse(d.date);
	d.car = +d.car;
	d.bike = +d.bike;
	d.moto = +d.moto;
});

var facts = crossfilter(myCSV);

var dateDim = facts.dimension(function (d) {return d.date});
var carDim = facts.dimension(function (d) {return d['car']});
var dgCar = dateDim.group().reduceSum(function (d) {return d['car']});
var bikeDim = facts.dimension(function (d) {return d['bike']});
var dgBike = dateDim.group().reduceSum(function (d) {return d['bike']});
var motoDim = facts.dimension(function (d) {return d['moto']});
var dgMoto = dateDim.group().reduceSum(function (d) {return d['moto']});

var minDate = myCSV[0].date; //new Date ("2016-01-01T08:00:00.000Z");
var maxDate = myCSV[myCSV.length-1].date;	//new Date ("2016-01-06T17:00:00.000Z");	

lc1
  .renderArea(false)
  .width(chartWidth)
  .height(chartHeight)
  .dimension(dateDim)
  .group(dgCar)
  .defined(function(d) {if(d.y !==null) {return d.y;}})
  .transitionDuration(1000)
  .margins({top: 30, right: 20, bottom: 35, left: 60})
  .yAxisLabel('Cars')
  .renderHorizontalGridLines(true)
  .brushOn(false)
  .x(d3.time.scale().domain([minDate,maxDate]));
lc1.yAxis().ticks(5);
lc1.xAxis().ticks(3);

lc2
.renderArea(false)
.width(chartWidth)
.height(chartHeight)
.dimension(dateDim)
.group(dgBike)
.defined(function(d) {if(d.y !==null) {return d.y;}})
.transitionDuration(1000)
.margins({top: 30, right: 20, bottom: 35, left: 60})
.yAxisLabel('Bikes')
.renderHorizontalGridLines(true)
.brushOn(false)
.x(d3.time.scale().domain([minDate,maxDate]));
lc2.yAxis().ticks(5);
lc2.xAxis().ticks(3);

lc3
.renderArea(false)
.width(chartHeight)
.height(250)
.dimension(dateDim)
.group(dgMoto)
.defined(function(d) {if(d.y !==null) {return d.y;}})
.transitionDuration(1000)
.margins({top: 30, right: 20, bottom: 35, left: 60})
.yAxisLabel('Motos')
.renderHorizontalGridLines(true)
.brushOn(false)
.x(d3.time.scale().domain([minDate,maxDate]));
lc3.yAxis().ticks(5);
lc3.xAxis().ticks(3);


lc1.on('renderlet', function(lc1) {
  	var thespot;
  	var allDots1 = lc1.selectAll('circle.dot');
    allDots1.filter(function(d,i){ //d==datum (obj), i==index (of datapoint on line)
  		  if (+d.x===testdate1) thespot = i;
	  });
    console.log('found spot: ' +thespot); //== 4th position on line
    //display red circle - NOT WORKING
    alldots1.filter((d,i) => i === thespot).classed('reddot',true);
    alldots2.filter((d,i) => i === thespot).classed('greendot',true);
    alldots3.filter((d,i) => i === thespot).classed('greendot',true);
    //display vertical line on all 3 graphs at same point - NOT WORKING
    alldots1
    	.filter((d,i) => +i === +thespot)
    	.append('line')
      .attr('x1', +testdate1)
      .attr('y1', chartHeight - margins.top)
      .attr('x2', +testdate1)
      .attr('y2', 0 + margins.top)
   		.style("stroke-width", 2)
   		.style("stroke", "red")
   		.style("fill", "none");
    alldots2
    	.filter((d,i) => +i === +thespot)
    	.append('line')
      .attr('x1', +testdate1)
      .attr('y1', chartHeight - margins.top)
      .attr('x2', +testdate1)
      .attr('y2', 0 + margins.top)
   		.style("stroke-width", 2)
   		.style("stroke", "red")
   		.style("fill", "none");
    alldots3
    	.filter((d,i) => +i === +thespot)
    	.append('line')
      .attr('x1', +testdate1)
      .attr('y1', chartHeight - margins.top)
      .attr('x2', +testdate1)
      .attr('y2', 0 + margins.top)
   		.style("stroke-width", 2)
   		.style("stroke", "red")
   		.style("fill", "none");
});//END lc1.renderlet

dc.renderAll();
dc.redrawAll();
.reddot {
  stroke: red !important;
  fill: red !important;
  fill-opacity: 1 !important;
}

.greendot {
  stroke: green;
  fill: green;
  fill-opacity: 1 !important;
}
<script src="//cdnjs.cloudflare.com/ajax/libs/crossfilter/1.3.1/crossfilter.min.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/d3/3.3.3/d3.min.js"></script>
<script src="//dc-js.github.io/dc.js/js/dc.js"></script>

<link href="//dc-js.github.io/dc.js/css/dc.css" rel="stylesheet" />


<svg id="line1"></svg>
<svg id="line2"></svg>
<svg id="line3"></svg>

最佳答案

通过使用 dc.js API,它有一个更简单(且可重用)的解决方案:

/* draw vertical lines code */
var line = d3.svg.line().interpolate('linear');
function draw_verticals(chart, points){
    // merge
    var selection = chart.g()
      .select('g.chart-body')
      .selectAll('path.horizontal')
      .data(points)
    // append
    selection.enter()
      .append('path')
      .attr('class', 'horizontal reddot')
      .attr('d', function(d) {
        var x = chart.x()(d);
        return line([
          [x, chart.y().range()[0]],
          [x, chart.y().range()[1]]
        ]);
      });
    // remove
    selection.exit().remove();
}
/*  ends here */

有了这个,您只需传递图表和要绘制垂直线的点数组,例如

draw_verticals(lc1, [testdate1, testdate2]);
draw_verticals(lc2, [testdate1, testdate2]);
draw_verticals(lc3, [testdate1, testdate2]);

Working demo

Reference

Reference's source code

额外的

要与刷子一起使用,您必须

1) 对于每个图表,删除动画之前的行,用

lcX.on('pretransition', function(c){
  draw_verticals(c, []);
});

2) 在 leaflet 事件中重绘线条

lcX.on('renderlet', function(c) {
  var thespot;
  var allDots = c.selectAll('circle.dot');
  allDots.filter(function(d, i) { //d==datum (obj), i==index (of datapoint on line)
    if (+d.x === testdate1) thespot = i;
  });
  // fixed `alldots1` to `allDots1`, now the red point renders correctly
  allDots.filter((d, i) => i === thespot).classed('reddot', true);
  draw_verticals(c, (thespot?[testdate1]:[]));
});

关于javascript - d3.js 按索引在特定点向折线图添加垂直线,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44211743/

相关文章:

javascript - 当用户使用 jquery 单击任意位置时切换和隐藏登录表单

javascript - 使用 JavaScript 将字母字符递增到下一个字符

javascript - 将 jQuery 的最后一位替换为 d3.js - 更改 css 属性的选择

javascript - dc.js - 如何获取数据集中列的平均值

javascript - 融合图表上的 HTML 标题和子标题

javascript - 如何将值从 grails 传递回 javascript 函数?

javascript - 使用多数组通过 dc.js、d3 和 crossfilter 在散点图上绘制数据

dc.js,防止饼图外部标签重叠

javascript - 读取D3中的字符串

javascript - d3.js 条形图转换无法正常工作