Reputation: 927
I have a div tag like in the following.
<div id="line_chart" ></div>
and then d3 code inside script tags to draw a graph.
var data = [{ "date": "2016.07.28", "close": 186889.45 }, { "date":
"2016.07.29", "close": 187156.54 }, { "date": "2016.08.01", "close":
187218.54 }, { "date": "2016.08.02", "close": 187624.73 }, { "date":
"2016.08.03", "close": 187198.72 }, { "date": "2016.08.05", "close":
185673.17 }, { "date": "2016.08.11", "close": 188383.55 }, { "date":
"2016.08.12", "close": 188033.59 }, { "date": "2016.08.13", "close":
187877.45 }, { "date": "2016.08.14", "close": 187877.45 }, { "date":
"2016.08.15", "close": 187935.9 }, { "date": "2016.08.16", "close":
180575.62 }, { "date": "2016.08.17", "close": 181022.03 }, { "date":
"2016.08.18", "close": 180294.82 }, { "date": "2016.08.19", "close":
194423.11 }];
margin = {
top: 20,
right: 20,
bottom: 20,
left: 100
};
var width = 960,
height = 500;
var vis = d3.select("#line_chart").append("svg")
.attr("width", width + margin.left +
margin.right)
.attr("height", height + margin.top +
margin.bottom);
var parseTime = d3.time.format("%Y.%m.%d").parse;
max_y = 0;
min_y = data[0].close;
var extent = d3.extent(data.map(function (d) { return d.date }))
max_x = extent[1];
min = extent[0];
for (i = 0; i < data.length; i++) {
max_y = Math.max(max_y, data[i].close);
min_y = Math.min(min_y, data[i].close);
}
var x = d3.time.scale()
.rangeRound([margin.left, width]);
xScale = x.domain(d3.extent(data, function (d) {
return parseTime(d.date);
}));
yScale = d3.scale.linear().range([height - margin.top, margin.bottom]).domain([min_y, max_y]),
xAxis = d3.svg.axis()
.scale(xScale),
yAxis = d3.svg.axis()
.scale(yScale)
.orient("left");
vis.append("svg:g")
.attr("class", "x axis")
.style({ 'stroke': 'Black', 'fill': 'none', 'stroke-width': '1px' })
.attr("transform", "translate(0," + (height - margin.bottom) + ")")
.call(xAxis);
vis.append("svg:g")
.attr("class", "y axis")
.style({ 'stroke': 'Black', 'fill': 'none', 'stroke-width': '1px' })
.attr("transform", "translate(" + (margin.left) + ",0)")
.call(yAxis);
var line = d3.svg.line()
.x(function (d) {
return xScale(parseTime(d.date));
})
.y(function (d) {
return yScale(d.close);
})
.interpolate("basis");
vis.append('svg:path')
.datum(data)
.attr("fill", "none")
.attr("stroke", "steelblue")
.attr("stroke-linejoin", "round")
.attr("stroke-linecap", "round")
.attr("stroke-width", 1.5)
.attr("d", line);
var hoverLineGroup = vis.append("g")
.attr("class", "hover-line");
var hoverLine = hoverLineGroup
.append("line")
.attr("stroke", "#000")
.attr("x1", 10).attr("x2", 10)
.attr("y1", 0).attr("y2", height);
var hoverTT = hoverLineGroup.append('text')
.attr("class", "hover-tex capo")
.attr('dy', "0.35em");
var cle = hoverLineGroup.append("circle")
.attr("r", 4.5);
var hoverTT2 = hoverLineGroup.append('text')
.attr("class", "hover-text capo")
.attr('dy', "0.55em");
hoverLineGroup.style("opacity", 1e-6);
var rectHover = vis.append("rect")
.data(data)
.attr("fill", "none")
.attr("class", "overlay")
.attr("width", width)
.attr("height", height);
vis
.on("mouseout", hoverMouseOff)
.on("mousemove", hoverMouseOn);
var bisectDate = d3.bisector(function (d) { return
parseTime(d.date); }).left;
function hoverMouseOn() {
var mouse_x = d3.mouse(this)[0];
var mouse_y = d3.mouse(this)[1];
var graph_y = yScale.invert(mouse_y);
var graph_x = xScale.invert(mouse_x);
var mouseDate = xScale.invert(mouse_x);
var i = bisectDate(data, mouseDate);
var d0 = data[i - 1]
var d1 = data[i];
var d = mouseDate - d0[0] > d1[0] - mouseDate ? d1 : d0;
hoverTT.text("Date: " + d.date);
hoverTT.attr('x', mouse_x);
hoverTT.attr('y', yScale(d.close));
hoverTT2.text("Portfolio Value: " + Math.round(d.close *
100) / 100)
.attr('x', mouse_x)
.attr('y', yScale(d.close) + 10);
cle
.attr('x', mouse_x)
.attr('y', mouse_y);
hoverLine.attr("x1", mouse_x).attr("x2", mouse_x)
hoverLineGroup.style({ 'font-weight': 'bold', 'opacity': 1
});
}
function hoverMouseOff() {
hoverLineGroup.style("opacity", 1e-6);
}
The graph is drawn according to the way I've want. That's fine. But when I open the javascript console ( ctrl + shift + J) there are several errors.
Uncaught ReferenceError: radOnResponseEnd is not defined
Uncaught TypeError: Cannot read property '0' of undefined
.
.
.
I think these errors are due to hoverMouseOn method. The following line is suspicious
var bisectDate = d3.bisector(function (d) { return parseTime(d.date);
}).left;
Because bisectDate is used inside function hoverMouseOn() which uses array "data" together with bisectDate. It seems like "data" is empty and that is why it says "cannot read property "0" of undefined".
Upvotes: 0
Views: 3153
Reputation: 102194
Your problem lies here:
var bisectDate = d3.bisector(function(d) {
return
parseTime(d.date);
}).left;
In JavaScript, when you put a new line after the return
...
return
foo;
... you will not return foo
. This is the same of:
return;
foo;
So, you are returning nothing (or undefined
).
Solution:
It has to be:
var bisectDate = d3.bisector(function(d) {
return parseTime(d.date);
}).left;
Here is your code with that change:
var data = [{
"date": "2016.07.28",
"close": 186889.45
}, {
"date": "2016.07.29",
"close": 187156.54
}, {
"date": "2016.08.01",
"close": 187218.54
}, {
"date": "2016.08.02",
"close": 187624.73
}, {
"date": "2016.08.03",
"close": 187198.72
}, {
"date": "2016.08.05",
"close": 185673.17
}, {
"date": "2016.08.11",
"close": 188383.55
}, {
"date": "2016.08.12",
"close": 188033.59
}, {
"date": "2016.08.13",
"close": 187877.45
}, {
"date": "2016.08.14",
"close": 187877.45
}, {
"date": "2016.08.15",
"close": 187935.9
}, {
"date": "2016.08.16",
"close": 180575.62
}, {
"date": "2016.08.17",
"close": 181022.03
}, {
"date": "2016.08.18",
"close": 180294.82
}, {
"date": "2016.08.19",
"close": 194423.11
}];
margin = {
top: 20,
right: 20,
bottom: 20,
left: 100
};
var width = 960,
height = 500;
var vis = d3.select("body").append("svg")
.attr("width", width + margin.left +
margin.right)
.attr("height", height + margin.top +
margin.bottom);
var parseTime = d3.time.format("%Y.%m.%d").parse;
max_y = 0;
min_y = data[0].close;
var extent = d3.extent(data.map(function(d) {
return d.date
}))
max_x = extent[1];
min = extent[0];
for (i = 0; i < data.length; i++) {
max_y = Math.max(max_y, data[i].close);
min_y = Math.min(min_y, data[i].close);
}
var x = d3.time.scale()
.rangeRound([margin.left, width]);
xScale = x.domain(d3.extent(data, function(d) {
return parseTime(d.date);
}));
yScale = d3.scale.linear().range([height - margin.top, margin.bottom]).domain([min_y, max_y]),
xAxis = d3.svg.axis()
.scale(xScale),
yAxis = d3.svg.axis()
.scale(yScale)
.orient("left");
vis.append("svg:g")
.attr("class", "x axis")
.style({
'stroke': 'Black',
'fill': 'none',
'stroke-width': '1px'
})
.attr("transform", "translate(0," + (height - margin.bottom) + ")")
.call(xAxis);
vis.append("svg:g")
.attr("class", "y axis")
.style({
'stroke': 'Black',
'fill': 'none',
'stroke-width': '1px'
})
.attr("transform", "translate(" + (margin.left) + ",0)")
.call(yAxis);
var line = d3.svg.line()
.x(function(d) {
return xScale(parseTime(d.date));
})
.y(function(d) {
return yScale(d.close);
})
.interpolate("basis");
vis.append('svg:path')
.datum(data)
.attr("fill", "none")
.attr("stroke", "steelblue")
.attr("stroke-linejoin", "round")
.attr("stroke-linecap", "round")
.attr("stroke-width", 1.5)
.attr("d", line);
var hoverLineGroup = vis.append("g")
.attr("class", "hover-line");
var hoverLine = hoverLineGroup
.append("line")
.attr("stroke", "#000")
.attr("x1", 10).attr("x2", 10)
.attr("y1", 0).attr("y2", height);
var hoverTT = hoverLineGroup.append('text')
.attr("class", "hover-tex capo")
.attr('dy', "0.35em");
var cle = hoverLineGroup.append("circle")
.attr("r", 4.5);
var hoverTT2 = hoverLineGroup.append('text')
.attr("class", "hover-text capo")
.attr('dy', "0.55em");
hoverLineGroup.style("opacity", 1e-6);
var rectHover = vis.append("rect")
.data(data)
.attr("fill", "none")
.attr("class", "overlay")
.attr("width", width)
.attr("height", height);
vis
.on("mouseout", hoverMouseOff)
.on("mousemove", hoverMouseOn);
var bisectDate = d3.bisector(function(d) {
return parseTime(d.date);
}).left;
function hoverMouseOn() {
var mouse_x = d3.mouse(this)[0];
var mouse_y = d3.mouse(this)[1];
var graph_y = yScale.invert(mouse_y);
var graph_x = xScale.invert(mouse_x);
var mouseDate = xScale.invert(mouse_x);
var i = bisectDate(data, mouseDate);
var d0 = data[i - 1] ? data[i - 1] : 0;
var d1 = data[i] ? data[i] : 0;
var d = mouseDate - d0[0] > d1[0] - mouseDate ? d1 : d0;
hoverTT.text("Date: " + d.date);
hoverTT.attr('x', mouse_x);
hoverTT.attr('y', yScale(d.close));
hoverTT2.text("Portfolio Value: " + Math.round(d.close *
100) / 100)
.attr('x', mouse_x)
.attr('y', yScale(d.close) + 10);
cle
.attr('cx', mouse_x)
.attr('cy', mouse_y);
hoverLine.attr("x1", mouse_x).attr("x2", mouse_x)
hoverLineGroup.style({
'font-weight': 'bold',
'opacity': 1
});
}
function hoverMouseOff() {
hoverLineGroup.style("opacity", 1e-6);
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>
PS: Mind that var d0 = data[i - 1];
and var d1 = data[i];
. They will be undefined
at the margins of the chart.
Upvotes: 1