0

我正在创建两个相关的堆积条形图。两个图表都必须包含一个线形光标。顶部图表的光标可以正常工作,但是底部图表中不会显示行光标。更糟糕的是,当我将鼠标放在底部图表上时,顶部图表中的线条光标会移动。需要修复哪些线条光标出现在底部图表中,或者不影响顶部图表或与顶部图表中的图表同步?d3js多个堆积条形图线光标出现在错误的图表中

注意:在说我不尊重我的代码中的“不要重复自己的原则”之前,请注意,Kent Beck说:“首先,让它工作,然后把它做好,最后让它快速工作”。另外,请随意跳过数据创建部分。 这里是我的代码:


          
  
   
 
    var app = {}; 
 

 
app.allBarsDatasets = [ 
 
    { 
 
     "xAxisTickValue": "10-1", 
 
     "barValue": 17 
 
    }, 
 
    { 
 
     "xAxisTickValue": "10-2", 
 
     "barValue": 17 
 
    }, 
 
    { 
 
     "xAxisTickValue": "10-3", 
 
     "barValue": 17 
 
    } 
 
]; 
 

 
app.allBarsDatasets2 = [ 
 
    [ 
 
     { 
 
      "xAxisTickValue": "10-1", 
 
      "barValue": 10 
 
     }, 
 
     { 
 
      "xAxisTickValue": "10-2", 
 
      "barValue": 6 
 
     }, 
 
     { 
 
      "xAxisTickValue": "10-3", 
 
      "barValue": 7 
 
     } 
 
    ], 
 
    [ 
 
     { 
 
      "xAxisTickValue": "10-1", 
 
      "barValue": 6 
 
     }, 
 
     { 
 
      "xAxisTickValue": "10-2", 
 
      "barValue": 8 
 
     }, 
 
     { 
 
      "xAxisTickValue": "10-3", 
 
      "barValue": 10 
 
     } 
 
    ] 
 
]; 
 

 
app.allLinesDatasets = 
 
    { 
 
     "points": [ 
 
      { 
 
       "x": 1, 
 
       "y": 10 
 
      }, 
 
      { 
 
       "x": 2, 
 
       "y": 8 
 
      }, 
 
      { 
 
       "x": 3, 
 
       "y": 14 
 
      } 
 
     ], 
 
     "color": "blue" 
 
    }; 
 
    
 
app.busStopsWaitTimes = { 
 
    "1": { 
 
     "days": { 
 
      "we": { 
 
       "10-1": [ 
 
        17, 
 
        14, 
 
        14, 
 
        4, 
 
        8, 
 
        13, 
 
        11, 
 
        3, 
 
        2, 
 
        14, 
 
        14, 
 
        8, 
 
        9, 
 
        1, 
 
        9, 
 
        9, 
 
        9, 
 
        17, 
 
        1, 
 
        20 
 
       ], 
 
       "10-2": [ 
 
        13, 
 
        12, 
 
        3, 
 
        5, 
 
        18, 
 
        14, 
 
        17, 
 
        5, 
 
        9, 
 
        12, 
 
        19, 
 
        3, 
 
        8, 
 
        9, 
 
        20, 
 
        3, 
 
        14, 
 
        5, 
 
        7, 
 
        13 
 
       ], 
 
       "10-3": [ 
 
        18, 
 
        8, 
 
        8, 
 
        7, 
 
        10, 
 
        20, 
 
        16, 
 
        17, 
 
        6, 
 
        13, 
 
        5, 
 
        11, 
 
        11, 
 
        14, 
 
        18, 
 
        17, 
 
        11, 
 
        17, 
 
        4, 
 
        3 
 
       ] 
 
      } 
 
     }, 
 
     "name": "Adderley" 
 
    } 
 
}; 
 

 
app.populateBusStopsWaitSelectionForm = function() {  
 
     let stopOptions = `<option value="">Select a stop</option>`; 
 
     $.each(app.busStopsWaitTimes, function (idx, stop) { 
 
      stopOptions += `<option value={"stopId":${idx}}>${stop.name}</option>`; 
 
     });   
 
     $("#busStopAnalysis_Stops").html(stopOptions); 
 
} 
 

 
app.populateBusStopsWaitSelectionForm(); 
 

 
$("#busStopAnalysis_Stops").change(function() { 
 
    let values = $("#busStopAnalysis_Stops").val(); 
 
    if (values !== "") { 
 
     values = JSON.parse(values); 
 
     let daysOptions = `<option value="">Select a day</option>`; 
 
     if ("we" in app.busStopsWaitTimes[values.stopId].days) { 
 
      daysOptions += `<option value={"dayKey":"we"}>Wednesday</option>` 
 
     } 
 
     $("#busStopAnalysis_Days").html(daysOptions); 
 
    } else { 
 
     $("#busStopAnalysis_Days").html("<option>Please select a route</option>"); 
 
    }      
 
}); 
 

 
$("#drawBusStopAnalysisChart").on("click", function (evt) { 
 
    evt.preventDefault(); 
 
    
 
    const stopInfo = JSON.parse($("#busStopAnalysis_Stops").val()); 
 
    const dayInfo = JSON.parse($("#busStopAnalysis_Days").val()); 
 
    if (stopInfo !== "" || dayInfo !== "") { 
 
     const allBarsDatasets = []; 
 
     const allBarsDatasets2 = [[],[]] 
 
     const allLinesdatasets = []; 
 
     const linePoints = []; 
 
     let i = 1; 
 
     $.each(app.busStopsWaitTimes[stopInfo.stopId]["days"][dayInfo.dayKey], function (idx, timeslot) { 
 
      timeslot.sort(function (a,b) { 
 
       return a - b; 
 
      }); 
 
      
 
      let Percentile25th = timeslot[parseInt(timeslot.length/4)]; 
 
      let Percentile50th = timeslot[parseInt(timeslot.length/2)]; 
 
      let Percentile75th = timeslot[parseInt((timeslot.length/4) * 3)]; 
 
      
 
      allBarsDatasets.push({ 
 
       xAxisTickValue: idx, 
 
       barValue: Percentile75th 
 
      }); 
 
      allBarsDatasets2[0].push({ 
 
       xAxisTickValue: idx, 
 
       barValue: Percentile25th 
 
      }); 
 
      allBarsDatasets2[1].push({ 
 
       xAxisTickValue: idx, 
 
       barValue: Percentile75th - Percentile25th 
 
      }); 
 
      
 
      linePoints.push({x : i, y : Percentile50th}); 
 
      i++; 
 
     }); 
 
     
 
     allLinesdatasets.push({points:linePoints,color:"blue"}); 
 

 
     app.drawBusStopAnalysisOneDayChart(allBarsDatasets, allBarsDatasets2, allLinesdatasets); 
 
     
 
    } 
 
}); 
 

 
app.drawBusStopAnalysisOneDayChart = function (allBarsDatasets, allBarsDatasets2, allLinesdatasets) { 
 
     app.allLinesdatasets = allLinesdatasets; 
 
    
 
    $("#busStopAnalysis_OneDayChart").html(""); 
 
    var barColor = '#384a60'; 
 
    
 
    // calculate total frequency by state for all segment. 
 
    // var fD = app.allBarsDatasets.map(function(d){return [d.xAxisTickValue,d.barValue];}); 
 
    var fD = allBarsDatasets.map(function(d){return [d.xAxisTickValue,d.barValue];}); 
 

 
    var margin = {top: 20, right: 100, bottom: 30, left: 100}, 
 
     width = 960 - margin.left - margin.right, 
 
     height = 500 - margin.top - margin.bottom;  
 
    
 

 
     var padding = 100; 
 
      
 
     //create svg for histogram. 
 
     var svg = d3.select("#busStopAnalysis_OneDayChart").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 + ")"); 
 

 
     // create function for x-axis mapping. 
 
     var x = d3.scale.ordinal().rangeRoundBands([0, width], 0.1, 0) 
 
       .domain(fD.map(function(d) { return d[0]; })); 
 

 
     // Add x-axis to the histogram svg. 
 
     svg.append("g").attr("class", "x axis") 
 
      .attr("transform", "translate(0," + height + ")") 
 
      .call(d3.svg.axis() 
 
       .scale(x) 
 
       .orient("bottom") 
 
       .innerTickSize(-height) 
 
       .outerTickSize(0) 
 
       .tickPadding(10)); 
 
     
 
     // create function for y-axis mapping. 
 
     var yMin = 0; 
 
     
 
     var yMax = d3.max(fD.map(function(d) { return d[1]; })); 
 
     
 
     var y = d3.scale.linear().range([height, 0]) 
 
      .domain([0, d3.max(fD, function(d) { return d[1]; })]); 
 
     
 
     var yScaleGridLines = d3.scale.linear() 
 
      .domain([0, yMax]) 
 
      .range([height, 0]); 
 
      
 
     var yAxisGridLines = d3.svg.axis() 
 
      .scale(yScaleGridLines) 
 
      .orient("left") 
 
      .innerTickSize(-width) 
 
      .outerTickSize(0) 
 
      .tickPadding(10); 
 

 
     svg.append("g") 
 
      .attr("class", "y axis") 
 
      .call(yAxisGridLines); 
 
    
 
    // You would think d3 draws bar by bar but it draws level by level 
 
    // therefore you need to create stacks which are sub-arrays whose contents 
 
    // are arrays of elements at the same level 
 
    // to achieve that 
 
    // call stack, 
 
    // call map and iterate over each array 
 
    // call map iterate over all elements within an array while creating points based on values to visualize  
 
    var layers = d3.layout.stack() (
 
     allBarsDatasets2.map(
 
      function(barDataset) { 
 
       return barDataset.map(
 
        function(d) { 
 
         return {x: d.xAxisTickValue, y:d.barValue}; 
 
        } 
 
        
 
       ) 
 
      } 
 
     ) 
 
    ); 
 
    
 
    var z = d3.scale.category10(); 
 

 
    var layer = svg.selectAll(".layer") 
 
     .data(layers) 
 
     .enter().append("g") 
 
     .attr("class", "layer") 
 
     .style("fill", function(d, i) { 
 
      var x; 
 
      if (i === 0) { 
 
       x = "transparent"; 
 
      } else { 
 
       // x = z(i); 
 
       x = "#686868"; 
 
      } 
 
      return x; 
 
     }); 
 
     
 
    var mouseG = d3.select("#busStopAnalysis_Charts").append("g") 
 
     .attr("class", "mouse-over-effects"); 
 

 
    // this is the vertical line 
 
    svg.append("path") 
 
     .attr("class", "mouse-line") 
 
     .style("stroke", "black") 
 
     .style("stroke-width", "1px") 
 
     .style("opacity", "1"); 
 
     
 
    var tooltip = d3.select("#busStopAnalysis_Charts") 
 
     .append('div') 
 
     .attr('id', 'tooltip'); 
 
     
 
    $("#tooltip").css('display', 'none'); 
 
     
 
    layer.selectAll("rect") 
 
     .data(function (d) { return d; }) 
 
     .enter().append("rect") 
 
     .attr("x", function (d) { return x(d.x); }) 
 
     .attr("y", function (d) { return y(d.y + d.y0); }) 
 
     .attr("height", function (d) { return y(d.y0) - y(d.y + d.y0); }) 
 
     .attr("width", x.rangeBand() - 1) 
 
     .on("mousemove", function (d) { 
 
     
 
      var mouse = d3.mouse(this); 
 
      // move the vertical line 
 
      d3.select(".mouse-line") 
 
       .attr("d", function() { 
 
       var d = "M" + mouse[0] + "," + height; 
 
       d += " " + mouse[0] + "," + 0; 
 
       return d; 
 
      });   
 
     }) 
 
     .on("mouseover", function (d) { 
 
      var mouse = d3.mouse(this); 
 
      
 
      console.log("first chart"); 
 
      console.log(mouse); 
 
      
 
      d3.select("#tooltip") 
 
       .style("left", mouse[0] + "px") 
 
       .style("top", mouse[1] + "px") 
 
       .style("width", "auto") 
 
       .style("height", "auto") 
 
       .html("Day: " + $("#busStopAnalysis_Days option:selected").text() + "<br>Time Range: " + d.x + "<br>Avg Wait: " + d.y); 
 

 
      $("#tooltip").css("display", ""); 
 
      
 
      app.drawAllDaysStopAnalysisChart(d);  
 

 
     }) 
 
     .on("mouseout", function() { 
 
      $("#tooltip").css("display", "none"); 
 
     }) 
 
     .on("click", function (d) { 
 
      app.drawAllDaysStopAnalysisChart(d);  
 
     }); 
 
    
 
    // Beginning of line things drawing 
 
    // Add min and max x and y borrowed from weird lines    
 
    var xMin = app.allLinesdatasets.reduce(function(pv,cv){ 
 
     var currentXMin = cv.points.reduce(function(pv,cv){ 
 
       return Math.min(pv,cv.x); 
 
      },100) 
 
       return Math.min(pv,currentXMin); 
 
      },100); 
 
    var xMax = app.allLinesdatasets.reduce(function(pv,cv){ 
 
     var currentXMax = cv.points.reduce(function(pv,cv){ 
 
       return Math.max(pv,cv.x); 
 
      },0) 
 
       return Math.max(pv,currentXMax); 
 
      },0); 
 
    
 
    var yMin = app.allLinesdatasets.reduce(function(pv,cv){ 
 
     var currentYMin = cv.points.reduce(function(pv,cv){ 
 
       return Math.min(pv,cv.y); 
 
      },100) 
 
       return Math.min(pv,currentYMin); 
 
      },100); 
 
    var yMax = app.allLinesdatasets.reduce(function(pv,cv){ 
 
     var currentYMax = cv.points.reduce(function(pv,cv){ 
 
       return Math.max(pv,cv.y); 
 
      },0) 
 
       return Math.max(pv,currentYMax); 
 
      },0); 
 
     
 
    var yScaleGridLines = d3.scale.linear() 
 
     .domain([0, yMax]) 
 
     .range([height, 0]); 
 
     
 
    var yAxisGridLines = d3.svg.axis() 
 
     .scale(yScaleGridLines) 
 
     .orient("left") 
 
     .innerTickSize(-width) 
 
     .outerTickSize(0) 
 
     .tickPadding(10); 
 
      
 
    var xScaleGridLines = {}; 
 
    
 
    xScaleGridLines = d3.scale.linear() 
 
     .domain([xMin, xMax]) 
 
     .range([0, width]); 
 

 
    var xAxisGridLines = d3.svg.axis() 
 
      .scale(xScaleGridLines) 
 
      .orient("bottom") 
 
      .innerTickSize(-height) 
 
      .outerTickSize(0) 
 
      .tickPadding(10);   
 

 
    var lineGridLines = d3.svg.line() 
 
     .interpolate('step-after') 
 
     .x(function(d) { return xScaleGridLines(d.x); }) 
 
     .y(function(d) { return yScaleGridLines(d.y); }); 
 
     
 
    $.each(app.allLinesdatasets, function (idx, dataset) {   
 
     svg.append("path") 
 
      .data([dataset.points]) 
 
      .attr("class", "line") 
 
      .attr("d", lineGridLines) 
 
      .style("stroke", function(){ 
 
       // return dataset.color; 
 
       return "#FF9900"; 
 
      }); 
 
    }); 
 
    
 
} 
 

 
/******************************************************************** 
 
* Append and Draw Second Chart 
 
********************************************************************/ 
 
app.drawAllDaysStopAnalysisChart = function drawAllDateStopAnalysis (timeRange) { 
 

 
     const stopInfo = JSON.parse($("#busStopAnalysis_Stops").val()); 
 
     
 
     const allBarsDatasets = []; 
 
     const allBarsDatasets2 = [[],[]] 
 
     const allLinesdatasets = []; 
 
     const linePoints = []; 
 
     if (stopInfo !== "" || dayInfo !== "") { 
 
      let i = 1; 
 
      $.each(app.busStopsWaitTimes[stopInfo.stopId]["days"], function (idx, day) { 
 
       const stopRangeWaitTimeInfo = day[timeRange.x]; 
 
       stopRangeWaitTimeInfo.sort(function (a,b) { 
 
        return a - b; 
 
       }); 
 
       
 
       let Percentile25th = stopRangeWaitTimeInfo[parseInt(stopRangeWaitTimeInfo.length/4)]; 
 
       let Percentile50th = stopRangeWaitTimeInfo[parseInt(stopRangeWaitTimeInfo.length/2)]; 
 
       let Percentile75th = stopRangeWaitTimeInfo[parseInt((stopRangeWaitTimeInfo.length/4) * 3)]; 
 
       
 
       allBarsDatasets.push({ 
 
        xAxisTickValue: idx, 
 
        barValue: Percentile75th 
 
       }); 
 
       allBarsDatasets2[0].push({ 
 
        xAxisTickValue: idx, 
 
        barValue: Percentile25th 
 
       }); 
 
       allBarsDatasets2[1].push({ 
 
        xAxisTickValue: idx, 
 
        barValue: Percentile75th - Percentile25th 
 
       }); 
 
       
 
       linePoints.push({x : i, y : Percentile50th}); 
 
       i++; 
 
      }); 
 
      
 
      allLinesdatasets.push({points:linePoints,color:"orange"}); 
 
      
 
     } 
 
    
 
    
 
    $("#busStopAnalysis_AllDaysChart").html(""); 
 
    var barColor = '#384a60'; 
 
    var fD = allBarsDatasets.map(function(d){return [d.xAxisTickValue,d.barValue];}); 
 

 
    var margin = {top: 20, right: 100, bottom: 30, left: 100}, 
 
     width = 960 - margin.left - margin.right, 
 
     height = 500 - margin.top - margin.bottom;  
 
    
 

 
    var padding = 100; 
 
     
 
    //create svg for histogram. 
 
    var svg = d3.select("#busStopAnalysis_AllDaysChart").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 + ")"); 
 

 
    // create function for x-axis mapping. 
 
    var x = d3.scale.ordinal().rangeRoundBands([0, width], 0.1, 0) 
 
      .domain(fD.map(function(d) { return d[0]; })); 
 

 
    // Add x-axis to the histogram svg. 
 
    svg.append("g").attr("class", "x axis") 
 
     .attr("transform", "translate(0," + height + ")") 
 
     .call(d3.svg.axis() 
 
      .scale(x) 
 
      .orient("bottom") 
 
      .innerTickSize(-height) 
 
      .outerTickSize(0) 
 
      .tickPadding(10)); 
 

 
    // create function for y-axis mapping. 
 
    var yMin = 0; 
 

 
    var yMax = d3.max(fD.map(function(d) { return d[1]; })); 
 

 
    var y = d3.scale.linear().range([height, 0]) 
 
     .domain([0, d3.max(fD, function(d) { return d[1]; })]); 
 

 
    var yScaleGridLines = d3.scale.linear() 
 
     .domain([yMin, yMax]) 
 
     .range([height, 0]); 
 
     
 
    var yAxisGridLines = d3.svg.axis() 
 
     .scale(yScaleGridLines) 
 
     .orient("left") 
 
     .innerTickSize(-width) 
 
     .outerTickSize(0) 
 
     .tickPadding(10); 
 

 
    svg.append("g") 
 
     .attr("class", "y axis") 
 
     .call(yAxisGridLines); 
 
    
 
    var layers = d3.layout.stack() (
 
     allBarsDatasets2.map(
 
      function(barDataset) { 
 
       return barDataset.map(
 
        function(d) { 
 
         return {x: d.xAxisTickValue, y:d.barValue}; 
 
        } 
 
        
 
       ) 
 
      } 
 
     ) 
 
    ); 
 
    
 
    var z = d3.scale.category10(); 
 

 
    var layer = svg.selectAll(".layer") 
 
     .data(layers) 
 
     .enter().append("g") 
 
     .attr("class", "layer") 
 
     .style("fill", function(d, i) { 
 
      var x; 
 
      if (i === 0) { 
 
       x = "transparent"; 
 
      } else { 
 
       x = "#FF9900"; 
 
      } 
 
      return x; 
 
     }); 
 
      
 
    // append a g for all the mouse over nonsense 
 
    var mouseG = svg.append("g") 
 
     .attr("class", "mouse-over-effects"); 
 

 
    // this is the vertical line 
 
    svg.append("path") 
 
     .attr("class", "mouse-line") 
 
     .style("stroke", "grey") 
 
     .style("stroke-width", "1px") 
 
     .style("opacity", "1"); 
 
     
 
    var tooltip = d3.select("#tooltip"); 
 
     
 
    $("#tooltip").css('display', 'none'); 
 
     
 
    layer.selectAll("rect") 
 
     .data(function (d) { return d; }) 
 
     .enter().append("rect") 
 
     .attr("x", function (d) { return x(d.x); }) 
 
     .attr("y", function (d) { return y(d.y + d.y0); }) 
 
     .attr("height", function (d) { return y(d.y0) - y(d.y + d.y0); }) 
 
     .attr("width", x.rangeBand() - 1) 
 
     .on("mousemove", function (d) { 
 
     
 
      var mouse = d3.mouse(this); 
 
      // move the vertical line 
 
      d3.select(".mouse-line") 
 
       .attr("d", function() { 
 
       var d = "M" + mouse[0] + "," + height; 
 
       d += " " + mouse[0] + "," + 0; 
 
       return d; 
 
      });   
 
     }) 
 
     .on("mouseover", function (d) { 
 
      var mouse = d3.mouse(this); 
 
      console.log("second chart"); 
 
      console.log(mouse); 
 
      
 
      tooltip.style("left", mouse[0] + "px") 
 
       .style("top", mouse[1] + "px") 
 
       .style("width", "auto") 
 
       .style("height", "auto") 
 
       .html("Day: " + $("#busStopAnalysis_Days option:selected").text() + "<br>Time Range: " + d.x + "<br>Avg Wait: " + d.y); 
 

 
      $("#tooltip").css("display", ""); 
 

 
     }) 
 
     .on("mouseout", function() { 
 
      $("#tooltip").css("display", "none"); 
 
     }); 
 
    
 
    // Beginning of line things drawing 
 
    // Add min and max x and y borrowed from weird lines    
 
    var xMin = app.allLinesdatasets.reduce(function(pv,cv){ 
 
     var currentXMin = cv.points.reduce(function(pv,cv){ 
 
       return Math.min(pv,cv.x); 
 
      },100) 
 
       return Math.min(pv,currentXMin); 
 
      },100); 
 
    var xMax = allLinesdatasets.reduce(function(pv,cv){ 
 
     var currentXMax = cv.points.reduce(function(pv,cv){ 
 
       return Math.max(pv,cv.x); 
 
      },0) 
 
       return Math.max(pv,currentXMax); 
 
      },0); 
 
    
 
    var yMin = allLinesdatasets.reduce(function(pv,cv){ 
 
     var currentYMin = cv.points.reduce(function(pv,cv){ 
 
       return Math.min(pv,cv.y); 
 
      },100) 
 
       return Math.min(pv,currentYMin); 
 
      },100); 
 
    var yMax = allLinesdatasets.reduce(function(pv,cv){ 
 
     var currentYMax = cv.points.reduce(function(pv,cv){ 
 
       return Math.max(pv,cv.y); 
 
      },0) 
 
       return Math.max(pv,currentYMax); 
 
      },0); 
 
     
 
    var yScaleGridLines = d3.scale.linear() 
 
     .domain([0, yMax]) 
 
     .range([height, 0]); 
 
     
 
    var yAxisGridLines = d3.svg.axis() 
 
     .scale(yScaleGridLines) 
 
     .orient("left") 
 
     .innerTickSize(-width) 
 
     .outerTickSize(0) 
 
     .tickPadding(10); 
 
      
 
    var xScaleGridLines = {}; 
 
    
 
    xScaleGridLines = d3.scale.linear() 
 
     .domain([xMin, xMax]) 
 
     .range([0, width]); 
 

 
    var xAxisGridLines = d3.svg.axis() 
 
      .scale(xScaleGridLines) 
 
      .orient("bottom") 
 
      .innerTickSize(-height) 
 
      .outerTickSize(0) 
 
      .tickPadding(10);   
 

 
    var lineGridLines = d3.svg.line() 
 
     .interpolate('step-after') 
 
     .x(function(d) { return xScaleGridLines(d.x); }) 
 
     .y(function(d) { return yScaleGridLines(d.y); }); 
 
     
 
    $.each(app.allLinesdatasets, function (idx, dataset) {   
 
     svg.append("path") 
 
      .data([dataset.points]) 
 
      .attr("class", "line") 
 
      .attr("d", lineGridLines) 
 
      .style("stroke", function(){ 
 
       // return dataset.color; 
 
       return "#FF3300"; 
 
      }); 
 
    }); 
 
    
 
} 
 
      
 
     
   
 
      #busStopAnalysis_Charts .axis path, 
 
      #busStopAnalysis_Charts .axis line{ 
 
       fill: none; 
 
       stroke: black; 
 
      } 
 
      #busStopAnalysis_Charts .line{ 
 
       fill: none; 
 
       stroke: blue; 
 
       stroke-width: 2px; 
 
      } 
 
      #busStopAnalysis_Charts .tick text{ 
 
       font-size: 12px; 
 
      } 
 
      #busStopAnalysis_Charts .tick line{ 
 
       opacity: 0.2; 
 
      } 
 
      #busStopAnalysis_Charts #tooltip { 
 
       position: absolute;   
 
       text-align: center; 
 
       color: white; 
 
       padding: 10px 10px 10px 10px; 
 
       display: inline-block; 
 
       font: 12px sans-serif;   
 
       background-color: #384a60; 
 
       border: 3px solid #2f3e50; 
 
       -webkit-border-radius: 30px; 
 
       -moz-border-radius: 30px; 
 
       border-radius: 30px; 
 
       -webkit-box-shadow: 2px 2px 4px #888; 
 
       -moz-box-shadow: 2px 2px 4px #888; 
 
       box-shadow: 2px 2px 4px #888; 
 
      } 
 
      #busStopAnalysis_Charts #tooltip.hidden { 
 
       display: none; 
 
      } 
 
      #busStopAnalysis_Charts #tooltip p { 
 
       margin: 0; 
 
       font-family: sans-serif; 
 
       font-size: 16px; 
 
       line-height: 20px; 
 
      } 
 
      
 
     
   
 
      <div id="busStopAnalysisChartArea_Form"> 
 
      <div id="busStopAnalysisChartArea_Form_TableRow"> 
 
      <div id="busStopAnalysisChartArea_Form_Stop"> 
 
       <label for="family" class="control-label"></label> 
 
       <select class="form-control dataset-column" style="width:auto;" id="busStopAnalysis_Stops"></select> 
 
      </div> 
 
      <div id="busStopAnalysisChartArea_Form_Days"> 
 
       <label for="family" class="control-label"></label> 
 
       <div> 
 
       <select class="form-control dataset-column" style="width:auto;float:left;" id="busStopAnalysis_Days"></select> 
 
       <a href="" id="drawBusStopAnalysisChart" title="Draw the chart">draw the chart</a> 
 
       </div> 
 
      </div> 
 
      </div> 
 
      </div> 
 
      <div id="busStopAnalysis_Charts"> 
 
      <div id="busStopAnalysis_OneDayChart"></div> 
 
      <div id="busStopAnalysis_AllDaysChart"></div> 
 
      <div> 
 
      <script src="https://d3js.org/d3.v3.min.js"></script> 
 
      <script src="https://code.jquery.com/jquery-2.2.4.min.js"></script> 
 
      
 
     

回答

0

的问题是我追加行光标这两个图表作为具有相同名称的类。我想d3很难确定哪一个我试图制作动画,所以它总是选择第一个。 解决的办法是用ID代替类,如下面的代码片段所示。

var app = {}; 
 

 
app.allBarsDatasets = [ 
 
    { 
 
     "xAxisTickValue": "10-1", 
 
     "barValue": 17 
 
    }, 
 
    { 
 
     "xAxisTickValue": "10-2", 
 
     "barValue": 17 
 
    }, 
 
    { 
 
     "xAxisTickValue": "10-3", 
 
     "barValue": 17 
 
    } 
 
]; 
 

 
app.allBarsDatasets2 = [ 
 
    [ 
 
     { 
 
      "xAxisTickValue": "10-1", 
 
      "barValue": 10 
 
     }, 
 
     { 
 
      "xAxisTickValue": "10-2", 
 
      "barValue": 6 
 
     }, 
 
     { 
 
      "xAxisTickValue": "10-3", 
 
      "barValue": 7 
 
     } 
 
    ], 
 
    [ 
 
     { 
 
      "xAxisTickValue": "10-1", 
 
      "barValue": 6 
 
     }, 
 
     { 
 
      "xAxisTickValue": "10-2", 
 
      "barValue": 8 
 
     }, 
 
     { 
 
      "xAxisTickValue": "10-3", 
 
      "barValue": 10 
 
     } 
 
    ] 
 
]; 
 

 
app.allLinesDatasets = 
 
    { 
 
     "points": [ 
 
      { 
 
       "x": 1, 
 
       "y": 10 
 
      }, 
 
      { 
 
       "x": 2, 
 
       "y": 8 
 
      }, 
 
      { 
 
       "x": 3, 
 
       "y": 14 
 
      } 
 
     ], 
 
     "color": "blue" 
 
    }; 
 
    
 
app.busStopsWaitTimes = { 
 
    "1": { 
 
     "days": { 
 
      "we": { 
 
       "10-1": [ 
 
        17, 
 
        14, 
 
        14, 
 
        4, 
 
        8, 
 
        13, 
 
        11, 
 
        3, 
 
        2, 
 
        14, 
 
        14, 
 
        8, 
 
        9, 
 
        1, 
 
        9, 
 
        9, 
 
        9, 
 
        17, 
 
        1, 
 
        20 
 
       ], 
 
       "10-2": [ 
 
        13, 
 
        12, 
 
        3, 
 
        5, 
 
        18, 
 
        14, 
 
        17, 
 
        5, 
 
        9, 
 
        12, 
 
        19, 
 
        3, 
 
        8, 
 
        9, 
 
        20, 
 
        3, 
 
        14, 
 
        5, 
 
        7, 
 
        13 
 
       ], 
 
       "10-3": [ 
 
        18, 
 
        8, 
 
        8, 
 
        7, 
 
        10, 
 
        20, 
 
        16, 
 
        17, 
 
        6, 
 
        13, 
 
        5, 
 
        11, 
 
        11, 
 
        14, 
 
        18, 
 
        17, 
 
        11, 
 
        17, 
 
        4, 
 
        3 
 
       ] 
 
      } 
 
     }, 
 
     "name": "Adderley" 
 
    } 
 
}; 
 

 
app.populateBusStopsWaitSelectionForm = function() {  
 
     let stopOptions = `<option value="">Select a stop</option>`; 
 
     $.each(app.busStopsWaitTimes, function (idx, stop) { 
 
      stopOptions += `<option value={"stopId":${idx}}>${stop.name}</option>`; 
 
     });   
 
     $("#busStopAnalysis_Stops").html(stopOptions); 
 
} 
 

 
app.populateBusStopsWaitSelectionForm(); 
 

 
$("#busStopAnalysis_Stops").change(function() { 
 
    let values = $("#busStopAnalysis_Stops").val(); 
 
    if (values !== "") { 
 
     values = JSON.parse(values); 
 
     let daysOptions = `<option value="">Select a day</option>`; 
 
     if ("we" in app.busStopsWaitTimes[values.stopId].days) { 
 
      daysOptions += `<option value={"dayKey":"we"}>Wednesday</option>` 
 
     } 
 
     $("#busStopAnalysis_Days").html(daysOptions); 
 
    } else { 
 
     $("#busStopAnalysis_Days").html("<option>Please select a route</option>"); 
 
    }      
 
}); 
 

 
$("#drawBusStopAnalysisChart").on("click", function (evt) { 
 
    evt.preventDefault(); 
 
    
 
    const stopInfo = JSON.parse($("#busStopAnalysis_Stops").val()); 
 
    const dayInfo = JSON.parse($("#busStopAnalysis_Days").val()); 
 
    if (stopInfo !== "" || dayInfo !== "") { 
 
     const allBarsDatasets = []; 
 
     const allBarsDatasets2 = [[],[]] 
 
     const allLinesdatasets = []; 
 
     const linePoints = []; 
 
     let i = 1; 
 
     $.each(app.busStopsWaitTimes[stopInfo.stopId]["days"][dayInfo.dayKey], function (idx, timeslot) { 
 
      timeslot.sort(function (a,b) { 
 
       return a - b; 
 
      }); 
 
      
 
      let Percentile25th = timeslot[parseInt(timeslot.length/4)]; 
 
      let Percentile50th = timeslot[parseInt(timeslot.length/2)]; 
 
      let Percentile75th = timeslot[parseInt((timeslot.length/4) * 3)]; 
 
      
 
      allBarsDatasets.push({ 
 
       xAxisTickValue: idx, 
 
       barValue: Percentile75th 
 
      }); 
 
      allBarsDatasets2[0].push({ 
 
       xAxisTickValue: idx, 
 
       barValue: Percentile25th 
 
      }); 
 
      allBarsDatasets2[1].push({ 
 
       xAxisTickValue: idx, 
 
       barValue: Percentile75th - Percentile25th 
 
      }); 
 
      
 
      linePoints.push({x : i, y : Percentile50th}); 
 
      i++; 
 
     }); 
 
     
 
     allLinesdatasets.push({points:linePoints,color:"blue"}); 
 

 
     app.drawBusStopAnalysisOneDayChart(allBarsDatasets, allBarsDatasets2, allLinesdatasets); 
 
     
 
    } 
 
}); 
 

 
app.drawBusStopAnalysisOneDayChart = function (allBarsDatasets, allBarsDatasets2, allLinesdatasets) { 
 
     app.allLinesdatasets = allLinesdatasets; 
 
    
 
    $("#busStopAnalysis_OneDayChart").html(""); 
 
    var barColor = '#384a60'; 
 
    
 
    // calculate total frequency by state for all segment. 
 
    // var fD = app.allBarsDatasets.map(function(d){return [d.xAxisTickValue,d.barValue];}); 
 
    var fD = allBarsDatasets.map(function(d){return [d.xAxisTickValue,d.barValue];}); 
 

 
    var margin = {top: 20, right: 100, bottom: 30, left: 100}, 
 
     width = 960 - margin.left - margin.right, 
 
     height = 500 - margin.top - margin.bottom;  
 
    
 

 
     var padding = 100; 
 
      
 
     //create svg for histogram. 
 
     var svg = d3.select("#busStopAnalysis_OneDayChart").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 + ")"); 
 

 
     // create function for x-axis mapping. 
 
     var x = d3.scale.ordinal().rangeRoundBands([0, width], 0.1, 0) 
 
       .domain(fD.map(function(d) { return d[0]; })); 
 

 
     // Add x-axis to the histogram svg. 
 
     svg.append("g").attr("class", "x axis") 
 
      .attr("transform", "translate(0," + height + ")") 
 
      .call(d3.svg.axis() 
 
       .scale(x) 
 
       .orient("bottom") 
 
       .innerTickSize(-height) 
 
       .outerTickSize(0) 
 
       .tickPadding(10)); 
 
     
 
     // create function for y-axis mapping. 
 
     var yMin = 0; 
 
     
 
     var yMax = d3.max(fD.map(function(d) { return d[1]; })); 
 
     
 
     var y = d3.scale.linear().range([height, 0]) 
 
      .domain([0, d3.max(fD, function(d) { return d[1]; })]); 
 
     
 
     var yScaleGridLines = d3.scale.linear() 
 
      .domain([0, yMax]) 
 
      .range([height, 0]); 
 
      
 
     var yAxisGridLines = d3.svg.axis() 
 
      .scale(yScaleGridLines) 
 
      .orient("left") 
 
      .innerTickSize(-width) 
 
      .outerTickSize(0) 
 
      .tickPadding(10); 
 

 
     svg.append("g") 
 
      .attr("class", "y axis") 
 
      .call(yAxisGridLines); 
 
    
 
    // You would think d3 draws bar by bar but it draws level by level 
 
    // therefore you need to create stacks which are sub-arrays whose contents 
 
    // are arrays of elements at the same level 
 
    // to achieve that 
 
    // call stack, 
 
    // call map and iterate over each array 
 
    // call map iterate over all elements within an array while creating points based on values to visualize  
 
    var layers = d3.layout.stack() (
 
     allBarsDatasets2.map(
 
      function(barDataset) { 
 
       return barDataset.map(
 
        function(d) { 
 
         return {x: d.xAxisTickValue, y:d.barValue}; 
 
        } 
 
        
 
       ) 
 
      } 
 
     ) 
 
    ); 
 
    
 
    var z = d3.scale.category10(); 
 

 
    var layer = svg.selectAll(".layer") 
 
     .data(layers) 
 
     .enter().append("g") 
 
     .attr("class", "layer") 
 
     .style("fill", function(d, i) { 
 
      var x; 
 
      if (i === 0) { 
 
       x = "transparent"; 
 
      } else { 
 
       x = "#686868"; 
 
      } 
 
      return x; 
 
     }); 
 
     
 
    var mouseG = d3.select("#busStopAnalysis_Charts").append("g") 
 
     .attr("id", "mouse-over-effects-one-day-chart"); 
 

 
    const lineCursorId = "mouse-line-one-day-chart"; 
 
    // this is the vertical line 
 
    svg.append("path") 
 
     .attr("id", lineCursorId) 
 
     .style("stroke", "black") 
 
     .style("stroke-width", "1px") 
 
     .style("opacity", "1"); 
 
     
 
     
 
    layer.selectAll("rect") 
 
     .data(function (d) { return d; }) 
 
     .enter().append("rect") 
 
     .attr("x", function (d) { return x(d.x); }) 
 
     .attr("y", function (d) { return y(d.y + d.y0); }) 
 
     .attr("height", function (d) { return y(d.y0) - y(d.y + d.y0); }) 
 
     .attr("width", x.rangeBand() - 1) 
 
     .on("mousemove", function (d) {   
 
      var mouse = d3.mouse(this); 
 
      app.drawStopAnalysisLineCursor(mouse, "#" + lineCursorId, height);  
 
     }) 
 
     .on("click", function (d) { 
 
      app.drawAllDaysStopAnalysisChart(d);  
 
     }); 
 
    
 
    // Beginning of line things drawing 
 
    // Add min and max x and y borrowed from weird lines    
 
    var xMin = app.allLinesdatasets.reduce(function(pv,cv){ 
 
     var currentXMin = cv.points.reduce(function(pv,cv){ 
 
       return Math.min(pv,cv.x); 
 
      },100) 
 
       return Math.min(pv,currentXMin); 
 
      },100); 
 
    var xMax = app.allLinesdatasets.reduce(function(pv,cv){ 
 
     var currentXMax = cv.points.reduce(function(pv,cv){ 
 
       return Math.max(pv,cv.x); 
 
      },0) 
 
       return Math.max(pv,currentXMax); 
 
      },0); 
 
    
 
    var yMin = app.allLinesdatasets.reduce(function(pv,cv){ 
 
     var currentYMin = cv.points.reduce(function(pv,cv){ 
 
       return Math.min(pv,cv.y); 
 
      },100) 
 
       return Math.min(pv,currentYMin); 
 
      },100); 
 
    var yMax = app.allLinesdatasets.reduce(function(pv,cv){ 
 
     var currentYMax = cv.points.reduce(function(pv,cv){ 
 
       return Math.max(pv,cv.y); 
 
      },0) 
 
       return Math.max(pv,currentYMax); 
 
      },0); 
 
     
 
    var yScaleGridLines = d3.scale.linear() 
 
     .domain([0, yMax]) 
 
     .range([height, 0]); 
 
     
 
    var yAxisGridLines = d3.svg.axis() 
 
     .scale(yScaleGridLines) 
 
     .orient("left") 
 
     .innerTickSize(-width) 
 
     .outerTickSize(0) 
 
     .tickPadding(10); 
 
      
 
    var xScaleGridLines = {}; 
 
    
 
    xScaleGridLines = d3.scale.linear() 
 
     .domain([xMin, xMax]) 
 
     .range([0, width]); 
 

 
    var xAxisGridLines = d3.svg.axis() 
 
      .scale(xScaleGridLines) 
 
      .orient("bottom") 
 
      .innerTickSize(-height) 
 
      .outerTickSize(0) 
 
      .tickPadding(10);   
 

 
    var lineGridLines = d3.svg.line() 
 
     .interpolate('step-after') 
 
     .x(function(d) { return xScaleGridLines(d.x); }) 
 
     .y(function(d) { return yScaleGridLines(d.y); }); 
 
     
 
    $.each(app.allLinesdatasets, function (idx, dataset) {   
 
     svg.append("path") 
 
      .data([dataset.points]) 
 
      .attr("class", "line") 
 
      .attr("d", lineGridLines) 
 
      .style("stroke", function(){ 
 
       // return dataset.color; 
 
       return "#FF9900"; 
 
      }); 
 
    }); 
 
    
 
} 
 

 
/******************************************************************** 
 
* Append and Draw Second Chart 
 
********************************************************************/ 
 
app.drawAllDaysStopAnalysisChart = function drawAllDateStopAnalysis (timeRange) { 
 

 
     const stopInfo = JSON.parse($("#busStopAnalysis_Stops").val()); 
 
     
 
     const allBarsDatasets = []; 
 
     const allBarsDatasets2 = [[],[]] 
 
     const allLinesdatasets = []; 
 
     const linePoints = []; 
 
     if (stopInfo !== "" || dayInfo !== "") { 
 
      let i = 1; 
 
      $.each(app.busStopsWaitTimes[stopInfo.stopId]["days"], function (idx, day) { 
 
       const stopRangeWaitTimeInfo = day[timeRange.x]; 
 
       stopRangeWaitTimeInfo.sort(function (a,b) { 
 
        return a - b; 
 
       }); 
 
       
 
       let Percentile25th = stopRangeWaitTimeInfo[parseInt(stopRangeWaitTimeInfo.length/4)]; 
 
       let Percentile50th = stopRangeWaitTimeInfo[parseInt(stopRangeWaitTimeInfo.length/2)]; 
 
       let Percentile75th = stopRangeWaitTimeInfo[parseInt((stopRangeWaitTimeInfo.length/4) * 3)]; 
 
       
 
       allBarsDatasets.push({ 
 
        xAxisTickValue: idx, 
 
        barValue: Percentile75th 
 
       }); 
 
       allBarsDatasets2[0].push({ 
 
        xAxisTickValue: idx, 
 
        barValue: Percentile25th 
 
       }); 
 
       allBarsDatasets2[1].push({ 
 
        xAxisTickValue: idx, 
 
        barValue: Percentile75th - Percentile25th 
 
       }); 
 
       
 
       linePoints.push({x : i, y : Percentile50th}); 
 
       i++; 
 
      }); 
 
      
 
      allLinesdatasets.push({points:linePoints,color:"orange"}); 
 
      
 
     } 
 
    
 
    
 
    $("#busStopAnalysis_AllDaysChart").html(""); 
 
    var barColor = '#384a60'; 
 
    var fD = allBarsDatasets.map(function(d){return [d.xAxisTickValue,d.barValue];}); 
 

 
    var margin = {top: 20, right: 100, bottom: 30, left: 100}, 
 
     width = 960 - margin.left - margin.right, 
 
     height = 500 - margin.top - margin.bottom;  
 
    
 

 
    var padding = 100; 
 
     
 
    //create svg for histogram. 
 
    var svg = d3.select("#busStopAnalysis_AllDaysChart").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 + ")"); 
 

 
    // create function for x-axis mapping. 
 
    var x = d3.scale.ordinal().rangeRoundBands([0, width], 0.1, 0) 
 
      .domain(fD.map(function(d) { return d[0]; })); 
 

 
    // Add x-axis to the histogram svg. 
 
    svg.append("g").attr("class", "x axis") 
 
     .attr("transform", "translate(0," + height + ")") 
 
     .call(d3.svg.axis() 
 
      .scale(x) 
 
      .orient("bottom") 
 
      .innerTickSize(-height) 
 
      .outerTickSize(0) 
 
      .tickPadding(10)); 
 

 
    // create function for y-axis mapping. 
 
    var yMin = 0; 
 

 
    var yMax = d3.max(fD.map(function(d) { return d[1]; })); 
 

 
    var y = d3.scale.linear().range([height, 0]) 
 
     .domain([0, d3.max(fD, function(d) { return d[1]; })]); 
 

 
    var yScaleGridLines = d3.scale.linear() 
 
     .domain([yMin, yMax]) 
 
     .range([height, 0]); 
 
     
 
    var yAxisGridLines = d3.svg.axis() 
 
     .scale(yScaleGridLines) 
 
     .orient("left") 
 
     .innerTickSize(-width) 
 
     .outerTickSize(0) 
 
     .tickPadding(10); 
 

 
    svg.append("g") 
 
     .attr("class", "y axis") 
 
     .call(yAxisGridLines); 
 
    
 
    var layers = d3.layout.stack() (
 
     allBarsDatasets2.map(
 
      function(barDataset) { 
 
       return barDataset.map(
 
        function(d) { 
 
         return {x: d.xAxisTickValue, y:d.barValue}; 
 
        } 
 
        
 
       ) 
 
      } 
 
     ) 
 
    ); 
 
    
 
    var z = d3.scale.category10(); 
 

 
    var layer = svg.selectAll(".layer") 
 
     .data(layers) 
 
     .enter().append("g") 
 
     .attr("class", "layer") 
 
     .style("fill", function(d, i) { 
 
      var x; 
 
      if (i === 0) { 
 
       x = "transparent"; 
 
      } else { 
 
       x = "#FF9900"; 
 
      } 
 
      return x; 
 
     }); 
 
      
 
    // append a g for all the mouse over nonsense 
 
    var mouseG = svg.append("g") 
 
     .attr("id", "mouse-over-effects-all-day-chart"); 
 

 
    let lineCursorId = "mouse-line-all-day-chart"; 
 
    // this is the vertical line 
 
    svg.append("path") 
 
     .attr("id", lineCursorId) 
 
     .style("stroke", "grey") 
 
     .style("stroke-width", "1px") 
 
     .style("opacity", "1"); 
 
     
 
    layer.selectAll("rect") 
 
     .data(function (d) { return d; }) 
 
     .enter().append("rect") 
 
     .attr("x", function (d) { return x(d.x); }) 
 
     .attr("y", function (d) { return y(d.y + d.y0); }) 
 
     .attr("height", function (d) { return y(d.y0) - y(d.y + d.y0); }) 
 
     .attr("width", x.rangeBand() - 1) 
 
     .on("mousemove", function (d) { 
 
      var mouse = d3.mouse(this); 
 
      app.drawStopAnalysisLineCursor(mouse, "#" + lineCursorId, height)  
 
     }); 
 
    
 
    // Beginning of line things drawing 
 
    // Add min and max x and y borrowed from weird lines    
 
    var xMin = app.allLinesdatasets.reduce(function(pv,cv){ 
 
     var currentXMin = cv.points.reduce(function(pv,cv){ 
 
       return Math.min(pv,cv.x); 
 
      },100) 
 
       return Math.min(pv,currentXMin); 
 
      },100); 
 
    var xMax = allLinesdatasets.reduce(function(pv,cv){ 
 
     var currentXMax = cv.points.reduce(function(pv,cv){ 
 
       return Math.max(pv,cv.x); 
 
      },0) 
 
       return Math.max(pv,currentXMax); 
 
      },0); 
 
    
 
    var yMin = allLinesdatasets.reduce(function(pv,cv){ 
 
     var currentYMin = cv.points.reduce(function(pv,cv){ 
 
       return Math.min(pv,cv.y); 
 
      },100) 
 
       return Math.min(pv,currentYMin); 
 
      },100); 
 
    var yMax = allLinesdatasets.reduce(function(pv,cv){ 
 
     var currentYMax = cv.points.reduce(function(pv,cv){ 
 
       return Math.max(pv,cv.y); 
 
      },0) 
 
       return Math.max(pv,currentYMax); 
 
      },0); 
 
     
 
    var yScaleGridLines = d3.scale.linear() 
 
     .domain([0, yMax]) 
 
     .range([height, 0]); 
 
     
 
    var yAxisGridLines = d3.svg.axis() 
 
     .scale(yScaleGridLines) 
 
     .orient("left") 
 
     .innerTickSize(-width) 
 
     .outerTickSize(0) 
 
     .tickPadding(10); 
 
      
 
    var xScaleGridLines = {}; 
 
    
 
    xScaleGridLines = d3.scale.linear() 
 
     .domain([xMin, xMax]) 
 
     .range([0, width]); 
 

 
    var xAxisGridLines = d3.svg.axis() 
 
      .scale(xScaleGridLines) 
 
      .orient("bottom") 
 
      .innerTickSize(-height) 
 
      .outerTickSize(0) 
 
      .tickPadding(10);   
 

 
    var lineGridLines = d3.svg.line() 
 
     .interpolate('step-after') 
 
     .x(function(d) { return xScaleGridLines(d.x); }) 
 
     .y(function(d) { return yScaleGridLines(d.y); }); 
 
     
 
    $.each(app.allLinesdatasets, function (idx, dataset) {   
 
     svg.append("path") 
 
      .data([dataset.points]) 
 
      .attr("class", "line") 
 
      .attr("d", lineGridLines) 
 
      .style("stroke", function(){ 
 
       return "#FF3300"; 
 
      }); 
 
    }); 
 
    
 
} 
 

 
app.drawStopAnalysisLineCursor = function (mouse, mouseLineId, height) { 
 
    // move the vertical line 
 
    d3.select(mouseLineId) 
 
     .attr("d", function() { 
 
     var d = "M" + (mouse[0] -2) + "," + height; 
 
     d += " " + (mouse[0] - 2) + "," + 0; 
 
     return d; 
 
    }); 
 
}
#busStopAnalysis_Charts .axis path, 
 
#busStopAnalysis_Charts .axis line{ 
 
    fill: none; 
 
    stroke: black; 
 
} 
 

 
#busStopAnalysis_Charts .line{ 
 
    fill: none; 
 
    stroke: blue; 
 
    stroke-width: 2px; 
 
} 
 

 
#busStopAnalysis_Charts .tick text{ 
 
    font-size: 12px; 
 
} 
 

 
#busStopAnalysis_Charts .tick line{ 
 
    opacity: 0.2; 
 
}
<div id="busStopAnalysisChartArea_Form"> 
 
    <div id="busStopAnalysisChartArea_Form_TableRow"> 
 
     <div id="busStopAnalysisChartArea_Form_Stop"> 
 
      <label for="family" class="control-label"></label> 
 
      <select class="form-control dataset-column" style="width:auto;" id="busStopAnalysis_Stops"></select> 
 
     </div> 
 
     <div id="busStopAnalysisChartArea_Form_Days"> 
 
      <label for="family" class="control-label"></label> 
 
      <div> 
 
       <select class="form-control dataset-column" style="width:auto;float:left;" id="busStopAnalysis_Days"></select> 
 
       <a href="" id="drawBusStopAnalysisChart" title="Draw the chart">draw the chart</a> 
 
      </div> 
 
     </div> 
 
    </div> 
 
</div> 
 
<div id="busStopAnalysis_Charts"> 
 
    <div id="busStopAnalysis_OneDayChart"></div> 
 
    <div id="busStopAnalysis_AllDaysChart"></div> 
 
</div> 
 
<script src="https://d3js.org/d3.v3.min.js"></script> 
 
<script src="https://code.jquery.com/jquery-2.2.4.min.js"></script>