Dynamically Update Multiple Charts in D3 - javascript

As stated by the title, I'm trying to dynamically update multiple line charts using D3. I have combined these two examples (http://bl.ocks.org/d3noob/6bd13f974d6516f3e491 and http://bl.ocks.org/d3noob/5987480). Only the first chart is updating with the second remaining static.
Here is the code:
<!DOCTYPE html>
<meta charset="utf-8">
<style> /* set the CSS */
body { font: 12px Arial;}
path {
stroke: steelblue;
stroke-width: 2;
fill: none;
}
.axis path,
.axis line {
fill: none;
stroke: grey;
stroke-width: 1;
shape-rendering: crispEdges;
}
</style>
<body>
<!-- load the d3.js library -->
<script src="http://d3js.org/d3.v3.min.js"></script>
<script>
// Set the dimensions of the canvas / graph
var margin = {top: 30, right: 20, bottom: 30, left: 50},
width = 400 - margin.left - margin.right,
height = 220 - margin.top - margin.bottom;
// Parse the date / time
var parseDate = d3.time.format("%H:%M:%S").parse;
// Set the ranges
var x = d3.time.scale().range([0, width]);
var y = d3.scale.linear().range([height, 0]);
// Define the axes
var xAxis = d3.svg.axis().scale(x)
.orient("bottom").ticks(5);
var yAxis = d3.svg.axis().scale(y)
.orient("left").ticks(5);
// Define the line
var valueline = d3.svg.line()
.x(function(d) { return x(d.date); })
.y(function(d) { return y(d.temperature); });
// Adds the svg canvas
var chart1 = d3.select("body")
.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 + ")");
// Get the data
d3.csv("output.csv", function(error, data) {
data.forEach(function(d) {
d.date = parseDate(d.date);
d.temperature = +d.temperature;
});
// Scale the range of the data
x.domain(d3.extent(data, function(d) { return d.date; }));
y.domain([0, d3.max(data, function(d) { return d.temperature; })]);
// Add the valueline path.
chart1.append("path")
.attr("class", "line")
.attr("d", valueline(data));
// Add the X Axis
chart1.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(xAxis);
// Add the Y Axis
chart1.append("g")
.attr("class", "y axis")
.call(yAxis);
});
// Adds the svg canvas
var chart2 = d3.select("body")
.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 + ")");
// Get the data
d3.csv("output2.csv", function(error, data) {
data.forEach(function(d) {
d.date = parseDate(d.date);
d.humidity = +d.humidity;
});
// Scale the range of the data
x.domain(d3.extent(data, function(d) { return d.date; }));
y.domain([0, d3.max(data, function(d) { return d.humidity; })]);
// Add the valueline path.
chart2.append("path")
.attr("class", "line")
.attr("d", valueline(data));
// Add the X Axis
chart2.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(xAxis);
// Add the Y Axis
chart2.append("g")
.attr("class", "y axis")
.call(yAxis);
});
//2 graph sample code ends here
var TemperatureInterval = setInterval(function() {
updateTemperatureData();
}, 5000);
var HumidityInterval = setInterval(function() {
updateHumidityData();
}, 7000);
function updateTemperatureData() {
// Get the data again
d3.csv("output2.csv", function(error, data) {
data.forEach(function(d) {
d.date = parseDate(d.date);
d.temperature = +d.temperature;
});
// Scale the range of the data again
x.domain(d3.extent(data, function(d) { return d.date; }));
y.domain([0, d3.max(data, function(d) { return d.temperature; })]);
// Select the section we want to apply our changes to
var chart1 = d3.select("body").transition();
// Make the changes
chart1.select(".line") // change the line
.duration(750)
.attr("d", valueline(data));
chart1.select(".x.axis") // change the x axis
.duration(750)
.call(xAxis);
chart1.select(".y.axis") // change the y axis
.duration(750)
.call(yAxis);
});
}
function updateHumidityData() {
// Get the data again
d3.csv("output2.csv", function(error, data) {
data.forEach(function(d) {
d.date = parseDate(d.date);
d.humidity = +d.humidity;
});
// Scale the range of the data again
x.domain(d3.extent(data, function(d) { return d.date; }));
y.domain([0, d3.max(data, function(d) { return d.humidity; })]);
// Select the section we want to apply our changes to
var chart2 = d3.select("body").transition();
// Make the changes
chart2.select(".line") // change the line
.duration(750)
.attr("d", valueline(data));
chart2.select(".x.axis") // change the x axis
.duration(750)
.call(xAxis);
chart2.select(".y.axis") // change the y axis
.duration(750)
.call(yAxis);
});
}
</script>
</body>
Thanks.

Here is a possible approach you can try:
// Adds the svg canvas
var chart1 = d3.select("body")
.append("svg")
.attr("class", "chart-1") // Be a little more specific and give a class or identifier to the chart
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
var chart2 = d3.select("body")
.append("svg")
.attr("class", "chart-2") // Be a little more specific and give a class or identifier to the chart
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
Add placeholders for the path and axis:
// Chart1 placeholders
chart1.append('path').attr('class', 'line');
chart1.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")");
chart1.append("g")
.attr("class", "y axis");
// Chart2 placeholders
chart2.append('path').attr('class', 'line');
chart2.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")");
chart2.append("g")
.attr("class", "y axis");
Since we don't have a data source we must simulate one:
function fetchData(selector) {
console.log('fetching');
return new Promise(function(resolve, reject) {
// Create new array, each time a different sized one with random values
var dataLength = Math.floor(Math.random() * 40) + 1;
var data = [];
for (var i = 0; i < dataLength; i++) {
data.push({
date: randomDate('2016-01-01', '2016-12-01'),
temperature: Math.floor(Math.random() * 40) + 1
});
}
setTimeout(function() { // Adding timeout to simulate latency
// resolve our promise with the newly created data and the selector of the chart we want to update
resolve({
data: data,
selector: selector
});
}, 4000)
})
}
function randomDate() { // helper function
var startDate = new Date(2012, 0, 1).getTime();
var endDate = new Date(2015, 0, 1).getTime();
var spaces = (endDate - startDate);
var timestamp = Math.round(Math.random() * spaces);
timestamp += startDate;
return new Date(timestamp);
}
Then let us create a new function which will update our charts:
function updateChart(resolved) { // receiving the resolved object from our promise
var data = resolved.data;
var selector = resolved.selector;
data.forEach(function(d) {
d.date = d.date;
d.temperature = +d.temperature;
});
// sort dates so we don't have issue of line screwing up
data.sort(function(a, b) {
return a.date - b.date;
});
// Scale the range of the data
x.domain(d3.extent(data, function(d) {
return d.date;
}));
y.domain([0, d3.max(data, function(d) {
return d.temperature;
})]);
// Since both charts have the same behaviour we can do this
var selection = d3.select("body").select(selector).transition();
// Add the valueline path.
selection.select(".line") // change the line
.duration(750)
.attr("d", valueline(data));
selection.select(".x.axis") // change the x axis
.duration(750)
.call(xAxis);
selection.select(".y.axis") // change the y axis
.duration(750)
.call(yAxis);
}
And finally set our update functions:
var HumidityInterval = setInterval(function() {
fetchData('.chart-1').then(updateChart);
}, 7000);
var TemperatureInterval = setInterval(function() {
fetchData('.chart-2').then(updateChart);
}, 7000);
Here is a plnkr with the working code if you have any doubts:
http://plnkr.co/edit/XlyME4tYlhoW4OgRW1dx?p=preview

Related

How do i use multiple csv files here and make the graph update itself every 5 seconds?

Here is my code. I m currently using 2 csv files and when i add third one nothing appears on the screen. How do i add multiple csv files here?
Graph should update itself for each csv files in every 5 seconds.
I need your help, what code has to be added to make it even more dynamic.
I tried this part in code to make it work with 3 csv, But it din work.
function updateData() {
// Get the data again
d3.csv("data-alt.csv", function(error, data) {
d3.csv("alt.csv-data", function(error, data) {
data.forEach(function(d) {
d.date = parseDate(d.date);
d.close = +d.close;
});
Here is the overall code.
<!DOCTYPE html>
<meta charset="utf-8">
<style> /* set the CSS */
body { font: 12px Arial;}
path {
stroke: steelblue;
stroke-width: 2;
fill: none;
}
.axis path,
.axis line {
fill: none;
stroke: grey;
stroke-width: 1;
shape-rendering: crispEdges;
}
</style>
<body>
<!-- load the d3.js library -->
<script src="http://d3js.org/d3.v3.min.js"></script>
<script>
// Set the dimensions of the canvas / graph
var margin = {top: 30, right: 20, bottom: 30, left: 50},
width = 600 - margin.left - margin.right,
height = 270 - margin.top - margin.bottom;
// Parse the date / time
var parseDate = d3.time.format("%d-%b-%y").parse;
// Set the ranges
var x = d3.time.scale().range([0, width]);
var y = d3.scale.linear().range([height, 0]);
// Define the axes
var xAxis = d3.svg.axis().scale(x)
.orient("bottom").ticks(5);
var yAxis = d3.svg.axis().scale(y)
.orient("left").ticks(5);
// Define the line
var valueline = d3.svg.line()
.x(function(d) { return x(d.date); })
.y(function(d) { return y(d.close); });
// Adds the svg canvas
var svg = d3.select("body")
.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 + ")");
// Get the data
d3.csv("data.csv", function(error, data) {
data.forEach(function(d) {
d.date = parseDate(d.date);
d.close = +d.close;
});
// Scale the range of the data
x.domain(d3.extent(data, function(d) { return d.date; }));
y.domain([0, d3.max(data, function(d) { return d.close; })]);
// Add the valueline path.
svg.append("path")
.attr("class", "line")
.attr("d", valueline(data));
// Add the X Axis
svg.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(xAxis);
// Add the Y Axis
svg.append("g")
.attr("class", "y axis")
.call(yAxis);
});
var inter = setInterval(function() {
updateData();
}, 5000);
// ** Update data section (Called from the onclick)
function updateData() {
// Get the data again
d3.csv("data-alt.csv", function(error, data) {
data.forEach(function(d) {
d.date = parseDate(d.date);
d.close = +d.close;
});
// Scale the range of the data again
x.domain(d3.extent(data, function(d) { return d.date; }));
y.domain([0, d3.max(data, function(d) { return d.close; })]);
// Select the section we want to apply our changes to
var svg = d3.select("body").transition();
// Make the changes
svg.select(".line") // change the line
.duration(750)
.attr("d", valueline(data));
svg.select(".x.axis") // change the x axis
.duration(750)
.call(xAxis);
svg.select(".y.axis") // change the y axis
.duration(750)
.call(yAxis);
});
}
</script>
</body>
You should break your function that handles parsing the result into another function, then just call d3.csv multiple times passing in the correct URL for the csv and the specific handler for that csv file.
Here is a quick snippet with the changes i suggested:
// Set the dimensions of the canvas / graph
var margin = {
top: 30,
right: 20,
bottom: 30,
left: 50
},
width = 600 - margin.left - margin.right,
height = 270 - margin.top - margin.bottom;
// Parse the date / time
var parseDate = d3.time.format("%d-%b-%y").parse;
// Set the ranges
var x = d3.time.scale().range([0, width]);
var y = d3.scale.linear().range([height, 0]);
// Define the axes
var xAxis = d3.svg.axis().scale(x)
.orient("bottom").ticks(5);
var yAxis = d3.svg.axis().scale(y)
.orient("left").ticks(5);
// Define the line
var valueline = d3.svg.line()
.x(function(d) {
return x(d.date);
})
.y(function(d) {
return y(d.close);
});
// Adds the svg canvas
var svg = d3.select("body")
.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 + ")");
function processDataCsv(error, data) {
data.forEach(function(d) {
d.date = parseDate(d.date);
d.close = +d.close;
});
// Scale the range of the data
x.domain(d3.extent(data, function(d) {
return d.date;
}));
y.domain([0, d3.max(data, function(d) {
return d.close;
})]);
// Add the valueline path.
svg.append("path")
.attr("class", "line")
.attr("d", valueline(data));
// Add the X Axis
svg.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(xAxis);
// Add the Y Axis
svg.append("g")
.attr("class", "y axis")
.call(yAxis);
}
function processAnotherCsv(error, data) {
// TODO: implement processing
}
function processYetAnotherCsv(error, data) {
// TODO: implement processing
}
// ** Update data section (Called from the onclick)
function updateData() {
// Get the data again
d3.csv("data.csv", processDataCsv);
d3.csv("another.csv", processAnotherCsv);
d3.csv("yetAnother.csv", processYetAnotherCsv);
}
// Get the data, just use the function you already wrote to do that
updateData();
var inter = setInterval(function() {
updateData();
}, 5000);
body {
font: 12px Arial;
}
path {
stroke: steelblue;
stroke-width: 2;
fill: none;
}
.axis path,
.axis line {
fill: none;
stroke: grey;
stroke-width: 1;
shape-rendering: crispEdges;
}
<script src="http://d3js.org/d3.v3.min.js"></script>

D3 Graph - Inject graph into div

I have some D3 javascript that works just fine. Here is the code if it helps. The trouble is, it loads in place of the javascript, which means I have to put the javascript in the right place in the HTML to position the graph.
what I want to be able to do is have this:
<div class="graph"></div>
and have the javascript inject the graph into that div.
Can anyone pleasse help me understand how to do this.
<!-- load the d3.js library -->
<script src="http://d3js.org/d3.v3.min.js"></script>
<script>
// Set the dimensions of the canvas / graph
var margin = {top: 30, right: 20, bottom: 30, left: 50},
width = 600 - margin.left - margin.right,
height = 270 - margin.top - margin.bottom;
// Parse the date / time
var parseDate = d3.time.format("%d-%b-%y").parse;
// Set the ranges
var x = d3.time.scale().range([0, width]);
var y = d3.scale.linear().range([height, 0]);
// Define the axes
var xAxis = d3.svg.axis().scale(x)
.orient("bottom").ticks(5);
var yAxis = d3.svg.axis().scale(y)
.orient("left").ticks(5);
// Define the line
var valueline = d3.svg.line()
.x(function(d) { return x(d.date); })
.y(function(d) { return y(d.close); });
// Adds the svg canvas
var svg = d3.select("body")
.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 + ")");
// Get the data
d3.csv("test3.csv", function(error, data) {
data.forEach(function(d) {
d.date = parseDate(d.date);
d.close = +d.close;
});
// Scale the range of the data
x.domain(d3.extent(data, function(d) { return d.date; }));
y.domain([0, d3.max(data, function(d) { return d.close; })]);
// Add the valueline path.
svg.append("path")
.attr("class", "line")
.attr("d", valueline(data));
// Add the X Axis
svg.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(xAxis);
// Add the Y Axis
svg.append("g")
.attr("class", "y axis")
.call(yAxis);
});
var inter = setInterval(function() {
updateData();
}, 5000);
// ** Update data section (Called from the onclick)
function updateData() {
// Get the data again
d3.csv("test3.csv", function(error, data) {
data.forEach(function(d) {
d.date = parseDate(d.date);
d.close = +d.close;
});
// Scale the range of the data again
x.domain(d3.extent(data, function(d) { return d.date; }));
y.domain([0, d3.max(data, function(d) { return d.close; })]);
// Select the section we want to apply our changes to
var svg = d3.select("body").transition();
// Make the changes
svg.select(".line") // change the line
.duration(750)
.attr("d", valueline(data));
svg.select(".x.axis") // change the x axis
.duration(750)
.call(xAxis);
svg.select(".y.axis") // change the y axis
.duration(750)
.call(yAxis);
});
}
</script>
This line:
d3.select("body")
.append("svg")
is telling d3 to append the svg to the body of the DOM. Try:
d3.select(".graph")
.append("svg")
Which finds your div by class name and appends the svg to that.

D3 v4 line chart with JSON dates

I've worked on this for a few days now, and I cant really get my line drawn and got some date formating problems I can't crack.
Using this D3 v3 fiddle as inspiration: http://jsfiddle.net/vmvp0zja/ I tried to convert it to D3 v4, but I can't really get my data drawn properly.
I am trying to draw several lines, but I cant even draw one..
Could you take a look and see what I am missing here? Thanks! :)
// JSON data:
var data = [
{"Date":"\/Date(1475272800000)\/","Open":0,"Closed":0},
{"Date":"\/Date(1475359200000)\/","Open":0,"Closed":0},
{"Date":"\/Date(1475445600000)\/","Open":0,"Closed":0},
{"Date":"\/Date(1475532000000)\/","Open":0,"Closed":0},
{"Date":"\/Date(1475618400000)\/","Open":0,"Closed":0},
{"Date":"\/Date(1475704800000)\/","Open":0,"Closed":0},
{"Date":"\/Date(1475791200000)\/","Open":0,"Closed":0},
{"Date":"\/Date(1475877600000)\/","Open":0,"Closed":0},
{"Date":"\/Date(1475964000000)\/","Open":0,"Closed":0},
{"Date":"\/Date(1476050400000)\/","Open":0,"Closed":0},
{"Date":"\/Date(1476136800000)\/","Open":0,"Closed":0},
{"Date":"\/Date(1476223200000)\/","Open":0,"Closed":0},
{"Date":"\/Date(1476309600000)\/","Open":0,"Closed":0},
{"Date":"\/Date(1476396000000)\/","Open":0,"Closed":0},
{"Date":"\/Date(1475445600000)\/","Open":1,"Closed":0},
{"Date":"\/Date(1475532000000)\/","Open":1,"Closed":0},
{"Date":"\/Date(1475618400000)\/","Open":2,"Closed":0},
{"Date":"\/Date(1475791200000)\/","Open":9,"Closed":0},
{"Date":"\/Date(1475964000000)\/","Open":1,"Closed":0},
{"Date":"\/Date(1475445600000)\/","Open":0,"Closed":1},
{"Date":"\/Date(1475532000000)\/","Open":0,"Closed":1},
{"Date":"\/Date(1475618400000)\/","Open":0,"Closed":1},
{"Date":"\/Date(1475964000000)\/","Open":0,"Closed":1}]
This is my D3 mess:
// linechart.js
var formatTime = d3.timeFormat("%Y-%m-%d");
data.forEach(function (d) {
var unixToISO = new Date(d.Date.match(/\d+/)[0]*1);
d.Date = formatTime(unixToISO);
d.Open = +d.Open;
d.Closed = +d.Closed;
console.log(d.Date);
return d;
});
var margin = {top: 30, right: 40, bottom: 30, left: 50 },
width = 600 - margin.left - margin.right,
height = 270 - margin.top - margin.bottom;
var x = d3.scaleTime()
.range([0, width]);
var y0 = d3.scaleLinear()
.range([height, 0]);
// Scale the range of the data
x.domain(d3.extent(data, function (d) { return d.Date; }));
y0.domain([
d3.min(data, function (d) { return Math.min(d.Open); }),
d3.max(data, function (d) { return Math.max(d.Open); })]);
var valueline1 = d3.line()
.x(function (d) { console.log(x(d.Date)); return x(d.Date); })
.y(function (d) { return y(d.Open); });
var svg = d3.select("body")
.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 + ")");
svg.append("g") // Add the X Axis
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(d3.axisBottom(x));
svg.append("g")
.attr("class", "y axis")
.style("fill", "steelblue")
.call(d3.axisLeft(y0));
svg.append("path") // Add the valueline path.
.data(data)
.attr("class", "line")
.attr("d", valueline1);
Help much appreciated in advance. I am probably overlooking something obvious.
Thank you!
Changes:
data.forEach(function(d) {
var unixToISO = new Date(d.Date.match(/\d+/)[0] * 1);
d.Date = unixToISO; // here
d.Open = +d.Open;
// (...)
var valueline1 = d3.line()
.x(function(d) {
console.log(x(d.Date));
return x(d.Date);
})
.y(function(d) {
return y0(d.Open); // here
});
// (...)
svg.append("path")
.data([data]) // here
.attr("class", "line")
.attr("d", valueline1);
and added x-axis labels with
svg.append("text")
.attr("transform", "translate(" + (width / 2) + " ," +
(height + margin.top + 20) + ")")
.style("text-anchor", "middle")
.text("Date");
BTW, your data is unsorted.
JSFiddle Demo
Docs reference

d3-tip doesn't work in a multiline chart

I am just learning how to use d3-tip in a multiline chart. I took this example for practising: http://bl.ocks.org/d3noob/d8be922a10cb0b148cd5
I've added d3-tip to the code but the tooltip doesn't appear. The chart is displayed correctly, but when I check the console: "Uncaught TypeError: Cannot read property 'value' of undefined" pointing to this code line:
.html(function(d) {
return "<b>" + d.value + "</b>";
})
Here I show you the script:
<script src="d3/d3.min.js" charset="utf-8"></script>
<script src="http://labratrevenge.com/d3-tip/javascripts/d3.tip.v0.6.3.js"></script>
<script>
// Set the dimensions of the canvas / graph
var margin = {top: 30, right: 20, bottom: 30, left: 50},
width = 600 - margin.left - margin.right,
height = 270 - margin.top - margin.bottom;
// Parse the date / time
var parseDate = d3.time.format("%b %Y").parse;
// Set the ranges
var x = d3.time.scale().range([0, width]);
var y = d3.scale.linear().range([height, 0]);
// Define the axes
var xAxis = d3.svg.axis().scale(x)
.orient("bottom").ticks(5);
var yAxis = d3.svg.axis().scale(y)
.orient("left").ticks(5);
var tip = d3.tip()
.attr('class', 'd3-tip')
.offset([0, 5])
.direction('n')
.html(function(d) {
return "<b>" + d.value + "</b>";
})
// Define the line
var priceline = d3.svg.line()
.x(function(d) { return x(d.date); })
.y(function(d) { return y(d.value); });
// Adds the svg canvas
var svg = d3.select("body")
.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 + ")");
svg.call(tip);
// Get the data
d3.csv("stocks.csv", function(error, data) {
data.forEach(function(d) {
d.date = parseDate(d.date);
d.value = +d.value;
});
// Scale the range of the data
x.domain(d3.extent(data, function(d) { return d.date; }));
y.domain([0, d3.max(data, function(d) { return d.value; })]);
// Nest the entries by symbol
var dataNest = d3.nest()
.key(function(d) {return d.name;})
.entries(data);
// Loop through each symbol / key
dataNest.forEach(function(d) {
svg.append("path")
.attr("class", "line")
.on('mouseover', tip.show)
.on('mouseout', tip.hide)
.attr("d", priceline(d.values))
});
// Add the X Axis
svg.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(xAxis);
// Add the Y Axis
svg.append("g")
.attr("class", "y axis")
.call(yAxis);
});
function type(d) {
d.value = +d.value;
return d;
}
</script>
I have changed many things, but I don't find the way. Any idea?
Thanks in advance.
You don't have any data bound to the elements you're calling the tooltip on. You don't need a loop, just use D3's data binding:
svg.selectAll("path")
.data(dataNest)
.enter()
.append("path")
.attr("class", "line")
.on('mouseover', tip.show)
.on('mouseout', tip.hide)
.attr("d", function(d) { return priceline(d.values); });
You probably also want to redefine your tooltip function:
.html(function(d) {
return "<b>" + d.key + "</b>";
});

How to make SVG/D3js clickable and get values?

Here is my entire JS code, I'm really just getting started based on some example.
I would like to be able to catch a click event, wether on the whole drawing, wether on the chart line and get y value for it.
onMouseOver and onMouseOut work as intended for now.
Thank you.
//Example may be interesting: http://bl.ocks.org/byrongibson/5232838
var parseDate = d3.time.format("%d-%b-%y").parse;
var svg, d3, x, y, valueline, xAxis, yAxis, width, height;
function CreateSvg()
{
// Set the dimensions of the canvas / graph
var margin = {top: 30, right: 20, bottom: 30, left: 50};
width = 600 - margin.left - margin.right;
height = 270 - margin.top - margin.bottom;
// Set the ranges
x = d3.time.scale().range([0, width]);
y = d3.scale.linear().range([height, 0]);
// Define the axes
xAxis = d3.svg.axis().scale(x)
.orient("bottom").ticks(5);
yAxis = d3.svg.axis().scale(y)
.orient("left").ticks(5);
// Define the line
valueline = d3.svg.line()
.x(function(d) { return x(d.date); })
.y(function(d) { return y(d.close); });
//var rect = d3.selectAll("rect");
// Adds the svg canvas
svg = d3.select("body")
.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 + ")").on("click", click)
;
}
function GetData(data)
{
data.forEach(function(d)
{
d.date = parseDate(d.date);
d.close = +d.close;
});
data.reverse();
data.push({date:parseDate('3-May-12'), close:Math.random() * 1200});
data.push({date:parseDate('4-May-12'), close:Math.random() * 1200});
data.reverse();
return data;
}
function Draw()
{
d3.csv("data.csv", function(error, data) {
data = GetData(data);
// Scale the range of the data
x.domain(d3.extent(data, function(d) { return d.date; }));
y.domain([0, d3.max(data, function(d) { return d.close; })]);
svg.text("");
// Add the valueline path.
svg.append("path")
.attr("class", "line")
.attr("d", valueline(data))
.on("mouseover", onMouseOver)
.on("mouseout", onMouseOut)
.on("click", click)
;
// Add the X Axis
svg.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(xAxis);
// Add the Y Axis
svg.append("g")
.attr("class", "y axis")
.call(yAxis);
});
}
function click() {
alert("onclick");
}
function onMouseOver(){
alert("mouseOver");
};
function onMouseOut(){
alert("mouseOut");
};
CreateSvg();
Draw();
Draw();

Categories