2017-04-19 1 views
0

Ich habe ein Diagramm erstellt, das Balken und Linie kombiniert. Was muss ich bei der Definition der Liniendiagramm-X-Achse ändern, damit die Linien perfekt mit dem Balken im Balkendiagramm ausgerichtet sind, was bedeutet, dass die Linie an der Stelle, an der ein Balken endet, von horizontal zu vertikal und umgekehrt verlaufen muss und ein anderer beginnt.D3.js Kombiniertes Balken- und Liniendiagramm Fehler bei der x-Achsenausrichtung Ausgabe

Das Ausführen des folgenden Code-Snippets wird Ihnen helfen, die leichte Verschiebung/Fehlausrichtung zu erkennen, auf die ich mich beziehe.

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; 
 
     let demoValue = 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)]; 
 
      let percentile100th = timeslot[timeslot.length - 1]; 
 
      
 
      allBarsDatasets.push({ 
 
       xAxisTickValue: idx, 
 
       barValue: percentile100th 
 
      }); 
 
      allBarsDatasets2[0].push({ 
 
       xAxisTickValue: idx, 
 
       barValue: percentile25th 
 
      }); 
 
      allBarsDatasets2[1].push({ 
 
       xAxisTickValue: idx, 
 
       barValue: percentile75th - percentile25th 
 
      }); 
 
      
 
      linePoints.push({x : i, y : (percentile75th - ((percentile75th - percentile25th)/2))}); 
 
      demoValue = demoValue + 1; 
 
      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) 
 
       .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 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; 
 
     }); 
 
     
 
     
 
     
 
    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; 
 
      });   
 
     }); 
 

 
    
 
    // 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 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"; 
 
      }); 
 
    }); 
 
    
 
}
#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>

Antwort

1

versuchen zu ändern:

var lineGridLines = d3.svg.line() 
    .interpolate('step-after') 
    .x(function(d) { return xScaleGridLines(d.x); }) 
    .y(function(d) { return yScaleGridLines(d.y); }); 

zu:

var lineGridLines = d3.svg.line() 
     .interpolate('step-after') 
     .x(function(d) { return xScaleGridLines(d.x) - x.rangeBand()/2; }) 
     .y(function(d) { return yScaleGridLines(d.y); });