I am trying to make a simple chart in d3, where I am plotting date (as string) vs frequency. But, I am getting error. Can someone help me out?
SNIPPET:
<html>
<head>
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.4.12/angular.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/1.12.4/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/4.3.0/d3.min.js"></script>
</head>
<body ng-app="myApp" ng-controller="myCtrl">
<svg width="1000" height="500"></svg>
<script>
//module declaration
var app = angular.module('myApp',[]);
//Controller declaration
app.controller('myCtrl', function($scope){
//custom data
var data = [
{x: "2016-01-10", y: "10.02"},
{x: "2016-02-10", y: "15.05"},
{x: "2016-03-10", y: "50.02"},
{x: "2016-04-10", y: "40.01"},
{x: "2016-05-10", y: "10.08"},
{x: "2016-06-10", y: "29.07"},
{x: "2016-07-10", y: "45.02"}
];
var mySVG = d3.select("svg");
var svgWidth = mySVG.attr("width");
var svgHeight = mySVG.attr("height");
var margins = {top: 20,right: 20,bottom: 20,left: 50};
var xRange = d3.scale.linear()
.range([margins.left, svgWidth - margins.right])
.domain([d3.min(data, function (d) {return d.x;}), d3.max(data, function (d) {return d.x;}) ]);
var yRange = d3.scale.linear()
.range([svgHeight - margins.top, margins.bottom])
.domain([d3.min(data, function (d) { return d.y; }), d3.max(data, function (d) { return d.y;}) ]);
var xAxis = d3.svg.axis()
.scale(xRange)
.tickSize(5)
.tickSubdivide(true);
var yAxis = d3.svg.axis()
.scale(yRange)
.tickSize(5)
.orient("left")
.tickSubdivide(true);
mySVG.append("svg:g")
.attr("class", "x axis")
.attr("transform", "translate(0," + (svgHeight - margins.bottom) + ")")
.call(xAxis);
mySVG.append("svg:g")
.attr("class", "y axis")
.attr("transform", "translate(" + (margins.left) + ",0)")
.call(yAxis);
var lineFunc = d3.svg.line()
.x(function (d) {
return xRange(d.x);
})
.y(function (d) {
return yRange(d.y);
})
.interpolate('linear');
mySVG.append("svg:path")
.attr("d", lineFunc(data))
.attr("stroke", "blue")
.attr("stroke-width", 2)
.attr("fill", "none");
});
</script>
</body>
</html>
** Error: **
var xRange = d3.scale.linear() <<<<< Error line
Please, help me in making the line chart along with x and y axis with date and frequency on them plotted. Kindly, help out.
Updated Snippet:
<html>
<head>
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.4.12/angular.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/1.12.4/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/4.3.0/d3.min.js"></script>
</head>
<body ng-app="myApp" ng-controller="myCtrl">
<svg width="1000" height="500"></svg>
<script>
//module declaration
var app = angular.module('myApp',[]);
//Controller declaration
app.controller('myCtrl', function($scope){
//custom data
var data = [
{x: "2016-01-10", y: "10.02"},
{x: "2016-02-10", y: "15.05"},
{x: "2016-03-10", y: "50.02"},
{x: "2016-04-10", y: "40.01"},
{x: "2016-05-10", y: "10.08"},
{x: "2016-05-10", y: "29.07"},
{x: "2016-05-10", y: "45.02"}
];
var mySVG = d3.select("svg");
var svgWidth = mySVG.attr("width");
var svgHeight = mySVG.attr("height");
var margins = {top: 20,right: 20,bottom: 20,left: 50};
var xRange = d3.scaleLinear()
.range([margins.left, svgWidth - margins.right])
.domain([d3.min(data, function (d) {return d.x;}), d3.max(data, function (d) {return d.x;}) ]);
var yRange = d3.scaleLinear()
.range([svgHeight - margins.top, margins.bottom])
.domain([d3.min(data, function (d) { return d.y; }), d3.max(data, function (d) { return d.y;}) ]);
var xAxis = d3.axisBottom(xRange)
.scale(xRange)
.tickSize(5);
var yAxis = d3.axisLeft(yRange)
.scale(yRange)
.tickSize(5)
.orient("left");
mySVG.append("svg:g")
.attr("class", "x axis")
.attr("transform", "translate(0," + (svgHeight - margins.bottom) + ")")
.call(xAxis);
mySVG.append("svg:g")
.attr("class", "y axis")
.attr("transform", "translate(" + (margins.left) + ",0)")
.call(yAxis);
var lineFunc = d3.line()
.x(function (d) {
return xRange(d.x);
})
.y(function (d) {
return yRange(d.y);
})
.curve(d3.curveLinear);
mySVG.append("svg:path")
.attr("d", lineFunc(data))
.attr("stroke", "blue")
.attr("stroke-width", 2)
.attr("fill", "none");
});
</script>
</body>
</html>
New Error:
You're using d3 v4.x, not the old v3. Thus, you have to modify your code.
These are the necessary changes:
var xRange = d3.scaleLinear()//keep the domain and range
var yRange = d3.scaleLinear()//keep the domain and range
var xAxis = d3.axisBottom(xRange)
.tickSize(5);
var yAxis = d3.axisLeft(yRange)
.tickSize(5);
var lineFunc = d3.line()//etc...
For the line generator, change interpolate for curve.
Also, get rid of tickSubdivide.
EDIT: you have additional problems in your fiddle: the values are strings, but they should be numbers. Besides that, if you're using dates, you'll have to parse them.
Here is your fiddle, without using the dates: https://jsfiddle.net/gerardofurtado/fawe63t8/
Related
I would like to draw a line by d3 with below codes.(http://jsfiddle.net/totaljj/L9n7qnv1)
It draws x,y-axis, but does not enter into the line function when appending d attribute.
You can debug on line number 104 to see that the code does not enter into the line function.
Any help would be appreciated.
<!DOCTYPE html>
<html>
<style>
.axis--x path {
display: none;
}
.line {
fill: none;
stroke: steelblue;
stroke-width: 1.5px;
}
</style>
<body>
<!-- Page Content -->
<div>
<svg width="430" height="250"></svg>
</div>
<section>
<script src="https://d3js.org/d3.v4.min.js"></script>
<script>
var data=
'{"recordsFiltered":5,"raCounts":[{"name":"comp_name","values":[{"date_":"2016","actual":170.0,"DT_RowId":"row_null"},{"date_":"2015","actual":198.0,"DT_RowId":"row_null"},{"date_":"2015","actual":149.0,"DT_RowId":"row_null"},{"date_":"2014","actual":197.0,"DT_RowId":"row_null"},{"date_":"2014","actual":146.0,"DT_RowId":"row_null"}],"DT_RowId":"row_null"}],"draw":null,"recordsTotal":5}';
var d = JSON.parse(data);
draw(d.raCounts);
function draw(data){
//svg
var svg = d3.select("svg"),
margin = {top: 100, right: 80, bottom: 30, left: 50},
width = svg.attr("width") - margin.left - margin.right,
height = svg.attr("height") - margin.top - margin.bottom,
g = svg.append("g").attr("transform", "translate(" + margin.left + "," + margin.top + ")");
//time
var parseTime = d3.timeParse("%Y%m%d");
//domain
// var x = d3.scaleTime().range([0, width]),
var x = d3.scaleLinear().range([0, width]),
y = d3.scaleLinear().range([height, 0]),
z = d3.scaleOrdinal(d3.schemeCategory10);
//line
var line = d3.line()
.curve(d3.curveBasis)
.x(function(d) {
return x(d.date_); })
.y(function(d) {
return y(d.actual); });
//domain
x.domain(d3.extent(data[0].values, function(d) {
return d.date_; }));
y.domain([
d3.min(data, function(c) {
return d3.min(c.values, function(d) {
return d.actual; }); }),
d3.max(data, function(c) {
return d3.max(c.values, function(d) {
return d.actual; }); })
]);
z.domain(data.map(function(c) {
return c.DT_RowId; }));
//axis
g.append("g")
.attr("class", "axis axis--x")
.attr("transform", "translate(0," + height + ")")
.call(d3.axisBottom(x));
g.append("g")
.attr("class", "axis axis--y")
.call(d3.axisLeft(y))
.append("text")
.attr("transform", "rotate(-90)")
.attr("y", 6)
.attr("dy", "0.71em")
.attr("fill", "#000")
.text("count");
var ra = g.selectAll(".ra")
.data(data)
.enter().append("g")
.attr("class", "ra");
//ra line
ra.append("path")
.attr("class", "line")
.attr("d",
function(d) { return
line(d.values); })
.style("stroke-dasharray", ("1","1"));
}
</script>
</section>
</body>
</html>
JavaScript doesn't always require semicolons at the end of a line. It will automatically insert them in certain situations, and the place where you call your line function is one of them:
.attr("d",
function(d) { return
line(d.values); })
The fix is therefore to remove the newline after return:
.attr("d",
function(d) { return line(d.values); })
I think both Gerardo Furtado's answer as well as Luke Woodward's answer have good points, but both circumvent the fact, that OP's solution is somewhat off the beaten track. To make full use of the data binding the typical approach would be something like the following:
//ra line
ra.selectAll("path.line")
.data(function(d) { return [d.values]; })
.enter().append("path")
.attr("class", "line")
.attr("d", line)
Passing just the line generator function get rids of the automatical semicolon insertion after the return statement. On the other hand, doing the data binding for the path.line element still allows for multiple lines drawn by the same statement.
Have a look at the following snippet for a working example:
var data =
'{"recordsFiltered":5,"raCounts":[{"name":"comp_name","values":[{"date_":"2016","actual":170.0,"DT_RowId":"row_null"},{"date_":"2015","actual":198.0,"DT_RowId":"row_null"},{"date_":"2015","actual":149.0,"DT_RowId":"row_null"},{"date_":"2014","actual":197.0,"DT_RowId":"row_null"},{"date_":"2014","actual":146.0,"DT_RowId":"row_null"}],"DT_RowId":"row_null"}],"draw":null,"recordsTotal":5}';
data = JSON.parse(data).raCounts;
//svg
var svg = d3.select("svg"),
margin = {
top: 100,
right: 80,
bottom: 30,
left: 50
},
width = svg.attr("width") - margin.left - margin.right,
height = svg.attr("height") - margin.top - margin.bottom,
g = svg.append("g").attr("transform", "translate(" + margin.left + "," + margin.top + ")");
//time
var parseTime = d3.timeParse("%Y%m%d");
//domain
// var x = d3.scaleTime().range([0, width]),
var x = d3.scaleLinear().range([0, width]),
y = d3.scaleLinear().range([height, 0]),
z = d3.scaleOrdinal(d3.schemeCategory10);
//line
var line = d3.line()
.curve(d3.curveBasis)
.x(function(d) {
return x(d.date_);
})
.y(function(d) {
return y(d.actual);
});
//domain
x.domain(d3.extent(data[0].values, function(d) {
return d.date_;
}));
y.domain([
d3.min(data, function(c) {
return d3.min(c.values, function(d) {
return d.actual;
});
}),
d3.max(data, function(c) {
return d3.max(c.values, function(d) {
return d.actual;
});
})
]);
z.domain(data.map(function(c) {
return c.DT_RowId;
}));
//axis
g.append("g")
.attr("class", "axis axis--x")
.attr("transform", "translate(0," + height + ")")
.call(d3.axisBottom(x));
g.append("g")
.attr("class", "axis axis--y")
.call(d3.axisLeft(y))
.append("text")
.attr("transform", "rotate(-90)")
.attr("y", 6)
.attr("dy", "0.71em")
.attr("fill", "#000")
.text("count");
var ra = g.selectAll(".ra")
.data(data)
.enter().append("g")
.attr("class", "ra");
//ra line
ra.selectAll("path.line")
.data(function(d) { return [d.values]; })
.enter().append("path")
.attr("class", "line")
.attr("d", line)
.style("stroke-dasharray", ("1", "1"));
<style> .axis--x path {
display: none;
}
.line {
fill: none;
stroke: steelblue;
stroke-width: 1.5px;
}
</style>
<script src="https://d3js.org/d3.v4.js"></script>
<svg width="430" height="250">
</svg>
You're not passing the correct data to your line generator. It should be:
ra.append("path")
.attr("class", "line")
.attr("d", line(data[0].values))
.style("stroke-dasharray", ("1", "1"));
Here is your updated fiddle: http://jsfiddle.net/67zs8ph7/
PS: this will plot just one line (see comment below)
In the following line chart, though the chart is plotted properly but the x and y axis with labels is not plotted properly. Can someone help me out with that?
SNIPPET:
<html>
<head>
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.4.12/angular.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/1.12.4/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/4.3.0/d3.min.js"></script>
</head>
<body ng-app="myApp" ng-controller="myCtrl">
<svg width="500" height="300"></svg>
<script>
//module declaration
var app = angular.module('myApp',[]);
//Controller declaration
app.controller('myCtrl', function($scope){
var data = [
{x: "2016-01-10", y: "10.02"},
{x: "2016-02-10", y: "15.02"},
{x: "2016-03-10", y: "50.02"},
{x: "2016-04-10", y: "40.02"},
{x: "2016-05-10", y: "10.02"}
];
var parseTime = d3.timeParse("%Y-%m-%d");
var xScale = d3.scaleTime().range([0,500]).domain(d3.extent(data, function(d){ return parseTime(d.x)}));
var yScale = d3.scaleLinear().range([300,0]).domain([0,50]);
//Plotting domain on x and y axis
var xAxis = d3.scaleBand().rangeRound([0, 500]).padding(0.6);
var yAxis = d3.scaleLinear().rangeRound([300, 0]);
xAxis.domain(data.map(function(d) { return d.letter; }));
yAxis.domain([0, d3.max(data, function(d) { return d.frequency; })]);
//Final printing of elements on svg
//Plortting of x-axis
d3.select("svg")
.append("g")
.attr("transform", "translate(0," + 300 + ")")
.call(d3.axisBottom(xAxis));
//Plotting of y-axis
d3.select("svg")
.append("g")
.call(d3.axisLeft(yAxis).ticks(10, "%"));
//the line function for path
var lineFunction = d3.line()
.x(function(d) {return xScale(parseTime(d.x)); })
.y(function(d) { return yScale(d.y); })
.curve(d3.curveLinear);
//Main svg container
var mySVG = d3.select("svg");
//defining the lines
var path = mySVG.append("path");
//plotting lines
path
.attr("d", lineFunction(data))
.attr("stroke",function() { return "hsl(" + Math.random() * 360 + ",100%,50%)"; })
.attr("stroke-width", 2)
.attr("fill", "none");
});
</script>
</body>
</html>
RESULT:
ISSUES:
The X-Axis is not coming
Labels on X-Axis missing
Lables on Y-Axis missing
Please, help me out to get the chart properly.
Regarding the y axis: you're not translating it from the origin position. It should be:
d3.select("svg")
.append("g")
.attr("transform", "translate(30, 0)")//30 here is just an example
.call(d3.axisLeft(yAxis).ticks(10, "%"));
Regarding the x axis: you're translating it all the way down to the height. It should be less than that:
d3.select("svg")
.append("g")
.attr("transform", "translate(0," + (height - 30) + ")")//30 is just an example
.call(d3.axisBottom(xAxis));
In a nutshell: set the margins properly and translate the axis according to those margins.
PS: nothing will show up in the ticks, because you don't have letter or frequency in your data.
Hi all i am trying to add dates in the d3.js how can i achieve this i am new to d3.js when i try add integers instead of date in the X-axis it is working good ..
How to declare date and assign them
I am here by attaching the JS and HTML file
thanks in advance:)
InitChart();
function InitChart() {
/*var lineData = [{
'x': 1,
'y': 5
}, {
'x': 20,
'y': 20
}, {
'x': 40,
'y': 10
}, {
'x': 60,
'y': 40
}, {
'x': 80,
'y': 5
}, {
'x': 100,
'y': 60
}];*/
var lineData=[{"y": 0.8076999999999999, "x": "2016-01-08 03:01:19.418110"}, {"y": 0.692666666666667, "x": "2016-01-08 05:10:19.838509"}, {"y": 0.5674333333333333, "x": "2016-01-08 09:54:13.022163"}]
var vis = d3.select("#visualisation"),
WIDTH = 1000,
HEIGHT = 500,
MARGINS = {
top: 20,
right: 20,
bottom: 20,
left: 50
},
xRange = d3.scale.linear().range([MARGINS.left, WIDTH - MARGINS.right]).domain([d3.min(lineData, function (d) {
return d.x;
}),
d3.max(lineData, function (d) {
return d.x;
})
]),
yRange = d3.scale.linear().range([HEIGHT - MARGINS.top, MARGINS.bottom]).domain([d3.min(lineData, function (d) {
return d.y;
}),
d3.max(lineData, function (d) {
return d.y;
})
]),
xAxis = d3.svg.axis()
.scale(xRange)
.tickSize(5)
.tickSubdivide(true),
yAxis = d3.svg.axis()
.scale(yRange)
.tickSize(5)
.orient("left")
.tickSubdivide(true);
vis.append("svg:g")
.attr("class", "x axis")
.attr("transform", "translate(0," + (HEIGHT - MARGINS.bottom) + ")")
.call(xAxis);
vis.append("svg:g")
.attr("class", "y axis")
.attr("transform", "translate(" + (MARGINS.left) + ",0)")
.call(yAxis);
var lineFunc = d3.svg.line()
.x(function (d) {
return xRange(d.x);
})
.y(function (d) {
return yRange(d.y);
})
.interpolate('linear');
vis.append("svg:path")
.attr("d", lineFunc(lineData))
.attr("stroke", "blue")
.attr("stroke-width", 2)
.attr("fill", "none");
}
and here is the HTML
enter code here
<!DOCTYPE html>
<html >
<head>
<meta charset="UTF-8">
<title> D3 trial </title>
<link rel="stylesheet" href="css/style.css">
</head>
<body>
<svg id="visualisation" width="400" height="500"></svg>
<script src='http://cdnjs.cloudflare.com/ajax/libs/jquery/2.1.3/jquery.min.js'> </script>
<script src='http://d3js.org/d3.v3.min.js'></script>
<script src="js/index.js"></script>
</body>
</html>
Have a look here, the example uses TypeScripit, but the concepts are the same. You basically need to use d3.time.scale() instead of d3.scale.linear(). You also need to parse your dates. Updated xRange should look like:
xRange = d3.time.scale().range([MARGINS.left, WIDTH - MARGINS.right]).domain(d3.extent(lineData, function (d) {
return new Date(d.x);
}))
I used the extent function instead of d3.min and d3.max, which has the same effect but with shorter notation.
I have built a chart like this example
http://bl.ocks.org/mbostock/4679202
here I would like to have y-axis labels for each series
the below code is my code to generate graph
since its a stacked layout. it feels a little complex for me imagine the y-axis transform attribute for each series
var margin = {top: 10, right: 5, bottom: -6, left: 5};
var width = $(div).width(),
height = $(div).height() - margin.top - margin.bottom;
var svg = d3.select(div).append('svg')
.attr('width',width)
.attr('height',height)
.append("g")
.attr("transform", "translate("+margin.left+"," + margin.top + ")");;
var nest = d3.nest()
.key(function(d) { return d.group; });
var stack = d3.layout.stack()
.values(function(d) { return d.values; })
.x(function(d) { return d.date; })
.y(function(d) { return d.value; })
.out(function(d, y0) { d.valueOffset = y0; });
var dataByGroup = nest.entries(data);
stack(dataByGroup);
var x = d3.scale.ordinal()
.rangeRoundBands([0, width-7], .25, 0);
var y0 = d3.scale.ordinal()
.rangeRoundBands([height-15, 0], .2);
var timeFormat = d3.time.format("%c");
var MinuteNameFormat = d3.time.format("%H:%M");
var y1 = d3.scale.linear();
var formatDate = function(d,i) {if(i%3 == 0){var date = new Date(parseInt(d)); return MinuteNameFormat(date);}else{return "";} };
var xAxis = d3.svg.axis()
.scale(x)
.orient("bottom")
.ticks(d3.time.minutes,15)
.tickFormat(formatDate);
var yAxis = d3.svg.axis()
.scale(y1)
.orient("Left")
.ticks(0)
.tickFormat(formalLabel);
x.domain(dataByGroup[0].values.map(function(d) { return d.date; }));
y0.domain(dataByGroup.map(function(d) { return d.key; }));
y1.domain([0, d3.max(data, function(d) { return d.value; })]).range([y0.rangeBand(), 0]);
var tooltip = d3.select(div)
.append("div")
.style("position", "absolute")
.style("z-index", "10").attr("class","tooltip")
.style("visibility", "hidden")
.style("background","#fff")
.style("border","1px solid #CCC")
.style("font-size", "11px")
.style("padding","11px")
.text("a simple tooltip");
var group = svg.selectAll(".group")
.data(dataByGroup)
.enter().append("g")
.attr("class", "group")
.attr("transform", function(d) { return "translate(0," + y0(d.key) + ")"; });
group.filter(function(d, i) { return !i; }).append("g")
.attr("class", "y axis")
.attr("transform", "translate(0," + y0.rangeBand() + ")")
.call(yAxis);
var tipText
var bars = group.selectAll("rect")
.data(function(d) { return d.values; })
.enter().append("g");
bars.append("rect")
.style("fill", function(d,i) { return getColor(d.ip); })
.attr("x", function(d) { return x(d.date); })
.attr("y", function(d) { return y1(d.value); })
.attr("width",x.rangeBand()) //x.rangeBand()
.attr("height", function(d) { return y0.rangeBand() - y1(d.value); });
group.filter(function(d, i) { return !i; }).append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + y0.rangeBand() + ")")
.call(xAxis);
this is the code for my d3 graph
can anyone suggest ??
This is entirely possible, but it would clutter you graph if you have more than 2 y-axis, one on the left side and one on the right.
Here is an example: http://bl.ocks.org/benjchristensen/2579619
You declare an axis with this code:
var yAxis = d3.svg.axis()
.scale(y1)
.orient("Left")
.ticks(0)
.tickFormat(formalLabel);
You just need to put 1 of this for each element, and you also need to declare a new y1,y2,y3... etc for each element. And finally you need to make sure each data is bound to a different axis y1,y2,y3... etc
Hope this helps.
I'm trying to build this trend component that is able to zoom and pan in data fetched with d3.json. First off, here's my code:
<script>
var margin = { top: 20, right: 80, bottom: 20, left: 50 },
width = $("#trendcontainer").width() - margin.left - margin.right,
height = 500 - margin.top - margin.bottom;
var format = d3.time.format("%Y-%m-%d").parse;
var x = d3.time.scale()
.domain([-width / 2, width / 2])
.range([0, width]);
var y = d3.scale.linear()
.domain([-height / 2, height / 2])
.range([height, 0]);
var color = d3.scale.category10();
var xAxis = d3.svg.axis()
.scale(x)
.orient("bottom")
.tickSize(-height);
var yAxis = d3.svg.axis()
.scale(y)
.orient("left")
.ticks(5)
.tickSize(-width);
var zoom = d3.behavior.zoom()
.x(x)
.y(y)
.scaleExtent([1, 10])
.on("zoom", zoomed);
var line = d3.svg.line()
.interpolate("basis")
.x(function(d) {
return x(d.date);
})
.y(function(d) {
return y(d.value);
});
var svg = d3.select(".panel-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 + ")")
.call(zoom);
d3.json('#Url.Action("DataBlob", "Trend", new {id = Model.Unit.UnitId, runId = 5})', function(error, json) {
$('#processing').hide();
color.domain(d3.keys(json[0]).filter(function(key) {
return key !== "Time" && key !== "Id";
}));
data.forEach(function(d) { var date = new Date(parseInt(d.Time.substr(6))); d.Time = date; });
var instruments = color.domain().map(function(name) {
return {
name: name,
values: data.map(function(d) {
return {
date: d.Time,
value: +d[name]
};
})
};
});
x.domain(d3.extent(data, function(d) { return d.Time; }));
y.domain([
d3.min(instruments, function(c) {
return d3.min(c.values, function(v) {
return v.value;
});
}),
d3.max(instruments, function(c) {
return d3.max(c.values, function(v) {
return v.value;
});
})
]);
svg.append("rect")
.attr("width", width)
.attr("height", height);
svg.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(xAxis);
svg.append("g")
.attr("class", "y axis")
.call(yAxis);
var instrument = svg.selectAll(".instrument")
.data(instruments)
.enter().append("g")
.attr("class", "instrument");
instrument.append("path")
.attr("class", "line")
.attr("d", function(d) {
return line(d.values);
})
.style("stroke", function(d) { return color(d.name); });
instrument.append("text")
.datum(function(d) {
return {
name: d.name,
value: d.values[d.values.length - 1]
};
})
.attr("transform", function(d) { return "translate(" + x(d.value.date) + "," + y(d.value.value) + ")"; })
.attr("x", 3)
.attr("dy", ".35em")
.text(function(d) { return d.name; });
});
function zoomed() {
svg.select(".x.axis").call(xAxis);
svg.select(".y.axis").call(yAxis);
svg.select(".x.grid")
.call(make_x_axis()
.tickSize(-height, 0, 0)
.tickFormat(""));
svg.select(".y.grid")
.call(make_y_axis()
.tickSize(-width, 0, 0)
.tickFormat(""));
svg.select(".line")
.attr("class", "line")
.attr("d", line);
};
var make_x_axis = function() {
return d3.svg.axis()
.scale(x)
.orient("bottom")
.ticks(5);
};
var make_y_axis = function() {
return d3.svg.axis()
.scale(y)
.orient("left")
.ticks(5);
};
</script>
Problem here being that the zooming / panning does not interact with my lines. The just stay the same, 'below' the zoomable / pannable grid. Also, one of the lines disappear when trying to zoom / pan and my console says the following:
Error: Problem parsing d="" - referring to the following snippet, last line:
function zoomed() {
svg.select(".x.axis").call(xAxis);
svg.select(".y.axis").call(yAxis);
svg.select(".x.grid")
.call(make_x_axis()
.tickSize(-height, 0, 0)
.tickFormat(""));
svg.select(".y.grid")
.call(make_y_axis()
.tickSize(-width, 0, 0)
.tickFormat(""));
svg.select(".line")
.attr("class", "line")
.attr("d", line);
};
Here's the content of my json result from the controller:
[{"Weight":0.0,"Speed":59.9,"Depth":362.24000,"Time":"2014-04-09T10:01:23","Id":0},{"Weight":10.0,"Speed":59.9,"Depth":394.07000,"Time":"2014-04-09T10:01:56","Id":1},{"Weight":971.0,"Speed":70.1,"Depth":425.84650,"Time":"2014-04-09T10:02:28","Id":2},{"Weight":0.0,"Speed":-29.9,"Depth":422.07465,"Time":"2014-04-09T10:03:00","Id":3},{"Weight":1321.0,"Speed":-21.6,"Depth":406.32840,"Time":"2014-04-09T10:03:32","Id":4},{"Weight":-6.0,"Speed":-30.0,"Depth":390.57880,"Time":"2014-04-09T10:04:04","Id":5},{"Weight":3.0,"Speed":59.9,"Depth":404.50380,"Time":"2014-04-09T10:04:36","Id":6},{"Weight":609.0,"Speed":59.9,"Depth":435.79380,"Time":"2014-04-09T10:05:08","Id":7},{"Weight":1.0,"Speed":59.9,"Depth":467.95280,"Time":"2014-04-09T10:05:40","Id":8},{"Weight":-2149.0,"Speed":34.6,"Depth":498.61060,"Time":"2014-04-09T10:06:12","Id":9},{"Weight":2.0,"Speed":59.9,"Depth":529.83060,"Time":"2014-04-09T10:06:44","Id":10}]
Trend looks like this in my view now, but the actual lines don't zoom or pan. Only the overlaying grid (black lines) does;
For simplicitys sake, I've considered just starting over, following the original example found here, but I really struggle with placing json-loaded data into this.
Hopefully, someone can help me figure this out :)
Thanks to Lars, I was finally able to solve this. Ultimately, I had to do some changes to my controller in addition to using this fiddle which assigns the scales to the zoom behaviour after setting the domains, so it returns a json string to my view like this:
string json = JsonConvert.SerializeObject(Model.Trend.ToArray());
return Json(json, JsonRequestBehavior.AllowGet);
This was due to the fact that some errors appeared when zooming / panning on the array returned without being serialized before returned to the view.
Also had to do the following for it to work:
d3.json('#Url.Action("DataBlob", "Trend", new {id = Model.Unit.UnitId, runId = 5})', function(error, tmparray) {
var json = JSON.parse(tmparray);
...
)};
If this step is skipped, my data will not be displayed properly for some reason, being squeezed to the left side of my graph.