I am a node noob, I am able to get express / swig to play nice, and display on screen, when I introduce my d3 code (which works by itself) the console comes back with Uncaught TypeError: Cannot read property 'forEach' of undefined(anonymous function) @ json:63event @ d3.js:504respond @ d3.js:1942
Things to note - the data.json
is in the same directory as templates.
Am I going about this the wrong way? Would it be better to do my d3 rendering inside node? If so, how do I pass that to a swig template etc?
Edit - I noticed in the dev tools the json wasn't being retrieved, the but SVG renders. I commented out the following since express was hijacking the get.
// app.get('/*', function (req, res) {
// res.send("404 bro");
// });
Now a new error has risen, which is a good sign!
GET http://localhost:3000/templates/data.json 404 (Not Found)
Again, sorry I am somewhat of a node nooby.
Update - here is my updated code
var data = require('./templates/data/data.json');
console.log("====== Loaded Jason ======" + JSON.stringify(data));
app.get('/json', function(req, res){
res.render('line', {'title' : 'First Swig Template'});
res.sendFile(data);
});
It comes back with
Unhandled rejection TypeError: undefined is not a function
Update - here is my updated code
app.get('/json', function(req, res){
res.render('line', {'title' : 'First Swig Template'});
res.sendFile('data.json', { root: path.join(__dirname, '/templates/data') });
});
Which comes back with
Error: Can't set headers after they are sent.
The Json is now displaying on the screen though.
Node code
// Retrieve
var MongoClient = require('mongodb').MongoClient;
//Swig for template
var swig = require('swig');
//consolidate -templating consolidation library
var cons = require("consolidate");
// Express
var express = require('express');
var app = express();
app.engine('html', cons.swig);
app.set('view engine', 'html');
app.set('views', __dirname + '/templates');
app.get('/swig', function(req, res){
res.render('home', {'title' : 'First Swig Template'});
});
app.get('/json', function(req, res){
res.render('line', {'title' : 'First Swig Template'});
});
//setup routes
app.get('/*', function (req, res) {
res.send("404 bro");
});
//setup server
var server = app.listen(3000, function () {
var host = server.address().address;
var port = server.address().port;
console.log('Example app listening at http://%s:%s', host, port);
});
// Connect to the db
MongoClient.connect("mongodb://localhost:27017/linejson", function(err, db) {
if(!err) {
console.log("We are connected");
}
var collection = db.collection('dummy');
// count records
collection.count(function(err, count) {
console.log("There are " + count + " records.");
});
collection.find().each(function(err, doc) {
if(doc != null) console.log("Doc from Each ");
console.dir(doc);
});
});
Html template + D3 code
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Data Visualization with D3 </title>
<!-- Bootstrap CDN CSS -->
<link href="//netdna.bootstrapcdn.com/bootstrap/3.1.1/css/bootstrap.min.css" rel="stylesheet">
<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>
</head>
<body>
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.5/d3.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.json("data.json", function(data) {
// data.forEach(function(d) {
// d.date = parseDate(d.date);
// d.close = +d.close;
// });
d3.json("data.json", 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);
});
</script>
</body>
</html>
The following line fixed it! Thanks for your inputs!