我正在创建两个相关的堆积条形图。两个图表都必须包含一个行光标。顶部图表的光标工作正常,但底部图表中没有显示行光标。更糟糕的是,当我将鼠标放在底部图表上方时,顶部图表中的线条光标会移动。什么需要修复a线条光标出现在底部图表中,是否不影响顶部图表或与顶部图表中的图表同步?
注意:在我的代码中说我不尊重“不要重复自己的原则”之前,请注意肯特贝克说:“首先,让它工作,然后做对,最后让它快速工作” 。另外,请随意跳过数据创建部分。 这是我的代码:
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 :(得分: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>