2 votes

d3.js Ajout d'une ligne verticale à un graphique linéaire à un point spécifique, par indice

J'ai des difficultés à faire apparaître une ligne verticale sur trois graphiques linéaires similaires (même ensemble de données).

Var testdate1 contient une date, qui se trouve sur le graphique (en haut de la lc1.on(renderlet) fonction) à la position 4 de l'index (4e "cercle.point" sur le graphique linéaire).

Comment ajouter une ligne verticale au graphique à cette position ? (Je souhaite ajouter des lignes verticales à la même position sur les trois graphiques linéaires, mais je pense que la procédure sera la même pour les trois).

De plus, pour une raison quelconque, je n'arrive pas à faire en sorte que le cercle situé à cet endroit se présente sous la forme d'un point rouge ou vert, alors qu'il fonctionne dans l'application cette réponse SO par davcs86 -- mais dans son exemple, nous localisons le point en utilisant l'axe des x (date), et ce code utilise le numéro d'index dans la collection alldotsN -- je ne vois pas non plus ce que je fais de mal ici.

<a href="http://jsfiddle.net/rvz1bnu5/" rel="nofollow noreferrer"><strong>jsFiddle to experiment with</strong></a>

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="stackoverflow.com//dc-js.github.io/dc.js/css/dc.css" rel="stylesheet" />

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

3voto

therobinkim Points 1645

http://jsfiddle.net/v6ehemnq/1/

Voici un résumé des changements que j'ai incorporés à partir des deux autres réponses.

D'abord, j'ai fait en sorte que le point rouge soit rendu correctement.

// fixed `alldots1` to `allDots1`, now the red point renders correctly
allDots1.filter((d, i) => i === thespot).classed('reddot', true);

Ensuite, j'ai tracé les lignes en regardant à l'œil où se trouvent le screenMinX et le screenMaxX. Vous pouvez utiliser une mesure plus précise en fonction de vos besoins.

var screenMinX = margins.left; // left most pixel coordinate of graph
var screenMaxX = margins.left + 408; // right most pixel coordinate of graph
var xScale = d3.time.scale().domain([minDate, maxDate]).range([screenMinX, screenMaxX]);
var vertLineXCoord = xScale(testdate1);

d3.select('#line1')
  .append('line')
  .attr('x1', vertLineXCoord)
  .attr('y1', chartHeight - margins.top)
  .attr('x2', vertLineXCoord)
  .attr('y2', 0 + margins.top)
  .style("stroke-width", 2)
  .style("stroke", "red")
  .style("fill", "none");

Notez que var margins n'a jamais existé auparavant, donc je l'ai créé pour permettre margins.left y margins.top pour être disponible.

3voto

davcs86 Points 3449

Il dispose d'une solution plus simple (et réutilisable) en utilisant l'API dc.js :

/* 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 */

Avec cette méthode, vous ne faites que passer le graphique et un tableau de points où vous voulez dessiner les lignes verticales, par exemple.

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

Démonstration de travail

Référence

Code source de la référence

Supplémentaire

Pour l'utiliser avec la brosse, vous devez

1) Pour chaque graphique, supprimer la ou les lignes avant l'animation, avec

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

2) Redessinez la (les) ligne(s) dans les leaflet événement

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]:[]));
});

2voto

ToxicTeacakes Points 552
var xScale = d3.time.scale().domain([minDate,maxDate]).range([screenMinX, screenMaxX]);

var vertLineXCoord = xScale(myCSV[pointYouWantToDrawLineAt].car); // or bike, or moto

vertLineXCoord doit être la coordonnée x de votre ligne verticale.

[screenMinX, screenMaxX] sont les coordonnées en pixels des points les plus à gauche et les plus à droite du graphique. Voir aquí pour plus d'explications sur le fonctionnement des balances.

2voto

Florian Points 1935

Une faute de frappe dans votre script : alldots1 devrait lire allDots1 . Une fois corrigé, le point rouge apparaît.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X