我创建了一个结合条和线路的图表。我需要更改线图x轴的定义,以使线与条形图中的条完全对齐,这意味着该行必须从水平到垂直到垂直,而在bar end的位置进行。另一个开始。
运行以下代码段将帮助您看到我指的略有偏移/未对准。
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>
尝试更改:
var lineGridLines = d3.svg.line()
.interpolate('step-after')
.x(function(d) { return xScaleGridLines(d.x); })
.y(function(d) { return yScaleGridLines(d.y); });
to:
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); });