I've an incredibly basic syntax question. I've been learning d3, SVG, and Javascript mostly by editing someone else's code, which is challenging.
The goal is to update a y axis after updating the data and the scale, which is based on the data. I want the axis--ticks and labels and all--to transition with the domain of the data. The axis isn't getting updated. The problem might be related to scope, or I'm referencing the wrong SVG element. (There are actually several plots getting updated simultaneously, but I'm just focusing on the axis of one of them here.)
function makeYaxis (chart, scale, nticks, label, width, height, xmf, visName)
{
var yAxis = d3.svg.axis()
.scale(scale)
.orient("left")
.ticks(nticks);
chart.append("svg:g")
.attr("class","y axis")
.append("g")
.attr("transform","translate(60,1)") // fix magic #
.call(yAxis);
var xMove = xmf.yylMarginFactor * width - 1;
var yMove = (((1 - xmf.xxbMarginFactor) * height +
xmf.xxtMarginFactor * height) / 2);
chart.append("svg:text")
.attr("class", visName + "xLabel")
.attr("x", 0)
.attr("y", 0)
.attr("dy", "-2.8em")
.text(label)
.attr("transform", "rotate(-90) translate(-" + yMove + "," + xMove + ")");
}
function makeYscale (plotMargin, thedata, xmf)
{
var dataMin = d3.min(thedata[0]);
var dataMax = d3.max(thedata[0]);
var yyMargin = d3.max([plotMargin * (dataMax - dataMin),0.05]);
var yy = d3.scale.linear()
.domain([dataMin - yyMargin, yyMargin + dataMax])
.range([(1 - xmf.xxbMarginFactor) * height, xmf.xxtMarginFactor * height]);
return yy;
}
// Set up this visualization
var chart = d3.select("#vis1")
.append("svg:svg")
.attr("class", "vis1chart")
.attr("width", width)
.attr("height", height);
var yy = makeYscale(plotMargin, thetas, xmf);
makeYaxis(chart, yy, nYTicks, "parameter", width, height, xmf, "vis1");
var points = chart.selectAll("circle.vis1points")
.data(thetas)
.enter().append("svg:circle")
.attr("class", "vis1points")
.attr("cx", function (d, i) { return xx(i); })
.attr("cy", function (d, i) { return yy(d); })
.attr("r", 3);
points.transition()
.attr("cx", function (d, i) { return xx(i); })
.attr("cy", yy)
.duration(dur);
vis1move();
function vis1move ()
{
function movePoints ()
{
var tmp = chart.selectAll(".vis1points").data(thetas[0], function (d, i) { return i; } );
var opa1 = points.style("stroke-opacity");
var opa2 = points.style("fill-opacity");
tmp
.enter().insert("svg:circle")
.attr("class", "vis1points")
.attr("cx", function (d, i) { return xx(i); })
.attr("cy", yy)
.attr("r", 3)
.style("stroke-opacity", opa1)
.style("fill-opacity", opa2);
tmp.transition()
.duration(10)
.attr("cx", function (d, i) { return xx(i); })
tmp.exit()
.transition().duration(10).attr("r",0).remove();
};
// (Code for updating theta, the data, goes here)
// Update axes for this vis
yy = makeYscale(plotMargin, thetas, xmf);
var transition = chart.transition().duration(10);
var yAxis = d3.svg.axis()
.scale(yy)
.orient("left")
.ticks(4);
transition.select("y axis").call(yAxis);
movePoints(); // Previously had been before axis update (fixed)
}
Sorry I can't get this self-contained.
Is transition.select.("y axis").call(yAxis) correct? Is there anything glaringly off here?
Edit: To keep things simple, I now have
// Update axes for this vis
yy = makeYscale(plotMargin, thetas, xmf);
var yAxis = d3.svg.axis().scale(yy);
chart.select("y axis").transition().duration(10).call(yAxis);
I'm wondering if something in the way I created the axis in the first place (in makeYaxis()) prevents me from selecting it properly. The yy function is returning the right values under the hood, and the data points are getting plotted and rescaled properly. It's just that the axis is "stuck."
Following meetamit's suggestions and the example here, I have stumbled on what appears to be a solution.
First, in function makeYaxis(), I removed the line .append("g"). I also updated the class name to yaxis. The function now reads
function makeYaxis (chart, scale, nticks, label, width, height, xmf, visName)
{
var yAxis = d3.svg.axis()
.scale(scale)
.orient("left")
.ticks(nticks);
chart.append("svg:g")
.attr("class","yaxis") // note new class name
// .append("g")
.attr("transform","translate(60,1)")
.call(yAxis);
// everything else as before
}
I then added an extra period in my call to select(".yaxis"):
chart.select(".yaxis").transition().duration(10).call(yAxis);
I would be very grateful if anyone could explain to me exactly why this solution appears to work.
Related
I'm trying to make a d3 realtime line chart with circle at the data point.
However, circles are gathered on the left side and it is not given to the data point.
This method is fine for static data to show circles with line chart.
chart.append('circle')
.data(data)
.attr('class', 'ciecle')
.attr("cy", line.x())
.attr("cy", line.y())
.attr("r", 5)
.attr("fill", 'blue');
However, it does not work with dynamically increasing data.
I want to move the circles with realtime line chat.
The follow code was forked from this URL
http://bl.ocks.org/KevinGutowski/131809cc7bcd1d37e10ca37b89da9630
Would you please let me how to change the code?
<svg id="chart"></svg>
<script src="http://d3js.org/d3.v4.min.js"></script>
<script>
var data = [];
var width = 500;
var height = 500;
var globalX = 0;
var duration = 100;
var max = 500;
var step = 10;
var chart = d3.select('#chart')
.attr('width', width + 50)
.attr('height', height + 50);
var x = d3.scaleLinear().domain([0, 500]).range([0, 500]);
var y = d3.scaleLinear().domain([0, 500]).range([500, 0]);
// -----------------------------------
var line = d3.line()
.x(function(d){ return x(d.x); })
.y(function(d){ return y(d.y); });
var smoothLine = d3.line().curve(d3.curveCardinal)
.x(function(d){ return x(d.x); })
.y(function(d){ return y(d.y); });
// -----------------------------------
// Draw the axis
var xAxis = d3.axisBottom().scale(x);
var axisX = chart.append('g').attr('class', 'x axis')
.attr('transform', 'translate(0, 500)')
.call(xAxis);
var path = chart.append('path');
var circle = chart.append('circle');
// Main loop
function tick() {
// Generate new data
var point = {
x: globalX,
y: ((Math.random() * 450 + 50) >> 0)
};
data.push(point);
globalX += step;
// Draw new line
path.datum(data)
.attr('class', 'smoothline')
.attr('d', smoothLine);
// Append circles. It should given to data point
chart.append('circle')
.data(data)
.attr('class', 'ciecle')
.attr("cy", line.x())
.attr("cy", line.y())
.attr("r", 5)
.attr("fill", 'blue');
// Shift the chart left
x.domain([globalX - (max - step), globalX]);
axisX.transition()
.duration(duration)
.ease(d3.easeLinear,.1)
.call(xAxis);
path.attr('transform', null)
.transition()
.duration(duration)
.ease(d3.easeLinear,.1)
.attr('transform', 'translate(' + x(globalX - max) + ')');
//move with line
circle.attr('transform', null)
.transition()
.duration(duration)
.ease(d3.easeLinear,.1)
.attr('transform', 'translate(' + x(globalX - max) + ')')
.on('end', tick);
// Remote old data (max 50 points)
if (data.length > 50) data.shift();
}
tick();
</script>
The coordinates of the path get repeatedly updated in the tick function (which repeatedly calls itself) using path.datum(data). You also need to update the locations of the circles on each tick using the adjusted (shifted) scale, which gets changed here:
x.domain([globalX - (max - step), globalX]);
To make the transitions smooth, you also need to update the transforms in each tick. You could update it for each circle and the path itself individually, but I just put both in a group (<g>) element and animate the whole group. Here's a working example:
http://bl.ocks.org/Sohalt/9715be30ba57e00f2275d49247fa7118/43a24a4dfa44738a58788d05230407294ab7a348
I would like to add a xAxis with custom values to my density plot (see Screenshot).
First density "violin" stands for "0-50", second for "51-100", third for "101-150" ... and seventh density for "301-350" passengers. It should look similar to what is shown in the following edited screenshot.
As I am a rookie in d3 and javascript I would appreciate detailed answers.
I am working with d3.js (v4).
Here is my current code:
function addViolin(svg, dataOfBin, heightPlot, widthPlot, domain, imposeMax, violinColor){
var data = d3.histogram()
.thresholds(resolution)
(dataOfBin);
var y = d3.scaleLinear()
.range([widthPlot/2, 0])
.domain([0, Math.max(imposeMax, d3.max(data, function(d) { return d.length; }))]);
var x = d3.scaleLinear()
.range([heightPlot, 0])
.domain(domain)
.nice();
var area = d3.area()
.curve(d3.curveCardinal)
.x(function(d) {
if(interpolation=="step-before")
return x(d.x1/2)
return x(d.x);
})
.y0(widthPlot/2)
.y1(function(d) { return y(d.length); });
var line=d3.line()
.curve(d3.curveCardinal)
.x(function(d) {
if(interpolation=="step-before")
return x(d.x1/2)
return x(d.x);
})
.y(function(d) { return y(d.length); });
var gPlus=svg.append("g")
var gMinus=svg.append("g")
gPlus.append("path")
.datum(data)
.attr("class", "area")
.attr("d", area)
.style("fill", violinColor);
gPlus.append("path")
.datum(data)
.attr("class", "violin")
.attr("d", line)
.style("stroke", violinColor);
gMinus.append("path")
.datum(data)
.attr("class", "area")
.attr("d", area)
.style("fill", violinColor);
gMinus.append("path")
.datum(data)
.attr("class", "violin")
.attr("d", line)
.style("stroke", violinColor);
gPlus.attr("transform", "rotate(90,0,0) translate(0,-"+widthPlot+")");//translate(0,-200)");
gMinus.attr("transform", "rotate(90,0,0) scale(1,-1)");
}
function addBoxPlot(svg, dataOfBin, heightPlot, widthPlot, domain, boxPlotWidth, boxColor, boxInsideColor){
}
var marginPlot={top:10, bottom:0, left:30, right:10};
var widthPlot=400;
var heightPlot=220;
var boxWidth=44;
var boxSpacing=10;
var resolution=1000;
var d3ObjId="svgElement1";
var interpolation='step-before';
function showView3(data){
var regionChart = document.getElementById("view3Diagram");
if(regionChart != null){
regionChart.innerHTML = "";
}
var domain=[0, 370];
var y = d3.scaleLinear()
.range([heightPlot-marginPlot.bottom, marginPlot.top])
.domain(domain);
var yAxis = d3.axisLeft()
.scale(y)
.ticks(5)
.tickSize(5,0,5);
var svg = d3.select("div#view3Diagram")
.append("div")
.classed("svg-container2", true)
.append("svg")
.attr("preserveAspectRatio", "xMinYMin meet")
.attr("viewBox", "0 0 430 430")
.classed("svg-content-responsive", true);
svg.append("line")
.attr("class", "boxplot")
.attr("x1", marginPlot.left)
.attr("x2", widthPlot-marginPlot.right)
.attr("y1", y(0))
.attr("y2", y(0));
for(var i=0; i<data.length; i++){
data[i].Haltezeiten=data[i].Haltezeiten.sort(d3.ascending)
var g=svg.append("g").attr("transform", "translate("+(i*(boxWidth+boxSpacing)+marginPlot.left)+",0)");
addViolin(g, data[i].Haltezeiten, heightPlot, boxWidth, domain, 0.25, "#424242");
addBoxPlot(g, data[i].Haltezeiten, heightPlot, boxWidth, domain, .15, "black", "white");
}
svg.append("g")
.attr('class', 'axis')
.attr("transform", "translate("+marginPlot.left+",0)")
.call(yAxis);
}
As you requested, I'll write a detailed explanation in this answer (however, this code doesn't seem the work of a rookie...).
As we can see, you use a for loop...
for(var i=0; i<data.length; i++){
... to create the <g> elements and, inside each one of them, the violin plots.
So, the most important thing here is data.length. We'll use that to set the domain or our point scale, which will be fundamental for customizing the axis' ticks later. Follow me:
If you pass d3.range(data.length) as the domain of the scale, you'll have an array of numbers with the same length of data.length. For instance, if data.length is 7, this is the result of d3.range(data.length):
[0, 1, 2, 3, 4, 5, 6]
Then, with this domain, we can create a customization in the axis using tickFormat. For that, I'm going to set a variable named steps, which says what's the gap between the values in the first tick. In your example:
var steps = 50;
With the domain and the step set, this is the math in the tickFormat:
.tickFormat(function(d, i) {
return i ? (d * steps) + 1 + " - " + (d * steps + steps)
: (d * steps) + " - " + (d * steps + steps);
});
In case you don't know, this is a ternary operator. It's basically:
condition ? expr1 : expr2
If condition is true, expr1 is executed, otherwise expr2 is executed.
Make sure that you pass the same range to the scale, and that you translate it accordingly.
Here is the running demo:
var svg = d3.select("svg");
var steps = 50;
var data = ["foo", "foo", "foo", "foo", "foo", "foo", "foo"];
var scale = d3.scalePoint()
.range([20, 470])
.domain(d3.range(data.length));
var axis = d3.axisBottom(scale)
.tickFormat(function(d, i) {
return i ? (d * steps) + 1 + " - " + (d * steps + steps) : (d * steps) + " - " + (d * steps + steps);
});
var gX = svg.append("g")
.attr("transform", "translate(0,50)")
.call(axis)
<script src="https://d3js.org/d3.v4.min.js"></script>
<svg width="500" height="500"></svg>
I have a visualization task that I need to make it done with d3.js. Here's my code.
var w = 700;
var h = 500;
var offset = 100;
var padding = 20;
var colors = d3.scale.category10();
var svg = d3.select("body")
.append("svg")
.attr("width", w)
.attr("height", h);
var texts = function(ds,ds2){
var stack = d3.layout.stack();
stack_data = stack(ds);
var xScale = d3.scale.ordinal()
.domain(d3.range(ds[0].length))
.rangeRoundBands([0, w-offset], 0.50);
var yScale = d3.scale.linear()
.domain([0,
d3.max(stack_data, function(d) {
return d3.max(d, function(d) {
return d.y0 + d.y -20;
});
})
])
.range([padding, h-50]);
var xAxis = d3.svg.axis()
.scale(xScale)
.orient("bottom")
.ticks(ds[0].length);
gs = svg.selectAll("g").data(stack_data);
for (var i5 = 0; i5 < ds.length; i5++) {
gs.enter()
.append("g")
.attr("class", "stacked_bars")
.attr("fill", function(d, i) {
return colors(i);
});
asd = gs.selectAll("rect").data(function(d) { return d; });
asd.enter().append("rect");
asd.transition()
.duration(1000)
.attr("x", function(d, i) {
return xScale(i);
})
.attr("y", function(d) {
return h - yScale(d.y0) - yScale(d.y);
})
.attr("height", function(d) {
return yScale(d.y);
})
.attr("width", xScale.rangeBand())
.attr("class", "rectbar");
};
gs.append("g") // add a group element to the svg
.attr("class", "axis") //Assign class "axis" to group
.attr("transform", "translate(0," + (h - padding) + ")") // shift the axis to bottom
.call(xAxis); // call the axis function
gs.exit().remove();
}
res = dataGenerator("Europe");
dataset = res[0];
dataset2 = res[1];
texts(dataset,dataset2);
d3.select("#selector").on("change", function() {
cont = d3.select(this).property('value');
res = dataGenerator(cont)
dataset = res[0]
dataset2 = res[1]
//svg.selectAll(".sym").remove()
texts(dataset,dataset2);
});
It basically gets the data and generates stacked bars. When user uses the select element on the page, it updates the data and generates new results. It successfully gets the first results and when user selects another option, it makes it happen also. But when user tries to use select part once again. It only generates bars for dataset's first item.
So, in this particular case I have countries and their data as numbers, at first load and first update it successfully shows all but when it comes to second update, it only generate bars for first country in dataset. It's been hours that I'm trying to fix this. I know I only have a little mistake but couldn't make it to solve.
Also here's the jsfiddle of the code: https://jsfiddle.net/510ep9ux/4/
Since I'm new at d3.js, I may not understand the update concept well.
So, any guesses?
Solved, using two separate functions textsInit and textsUpdate :
https://jsfiddle.net/qxqdp36x/2/
Essentially you need to separate initialization and update logic, and avoid re-creating elements when updating, that causes unintended behaviours.
Also, the variables gs and asd needs to be global to be accessible to both functions.
var textsInit = function(ds, ds2) {
var stack = d3.layout.stack();
stack_data = stack(ds);
var xScale = d3.scale.ordinal()
.domain(d3.range(ds[0].length))
.rangeRoundBands([0, w - offset], 0.50);
var yScale = d3.scale.linear()
.domain([0,
d3.max(stack_data, function(d) {
return d3.max(d, function(d) {
return d.y0 + d.y - 20;
});
})
])
.range([padding, h - 50]);
var xAxis = d3.svg.axis()
.scale(xScale)
.orient("bottom")
.ticks(ds[0].length);
gs = svg.selectAll("g").data(stack_data);
bars = gs.enter();
bars.append("g")
.attr("class", "stacked_bars")
.attr("fill", function(d, i) {
return colors(i);
});
asd = gs.selectAll("rect").data(function(d) {
return d;
});
asd.enter().append("rect");
asd.transition()
.duration(1000)
.attr("x", function(d, i) {
return xScale(i);
})
.attr("y", function(d) {
return h - yScale(d.y0) - yScale(d.y);
})
.attr("height", function(d) {
return yScale(d.y);
})
.attr("width", xScale.rangeBand())
.attr("class", "rectbar");
gs.append("g") // add a group element to the svg
.attr("class", "axis") //Assign class "axis" to group
.attr("transform", "translate(0," + (h - padding) + ")") // shift the axis to bottom
.call(xAxis); // call the axis function
}
And:
var textsUpdate = function(ds, ds2) {
var stack = d3.layout.stack();
stack_data = stack(ds);
var xScale = d3.scale.ordinal()
.domain(d3.range(ds[0].length))
.rangeRoundBands([0, w - offset], 0.50);
var yScale = d3.scale.linear()
.domain([0,
d3.max(stack_data, function(d) {
return d3.max(d, function(d) {
return d.y0 + d.y - 20;
});
})
])
.range([padding, h - 50]);
gs.data(stack_data);
asd = gs.selectAll("rect").data(function(d) { return d; });
asd.transition()
.duration(1000)
.attr("x", function(d, i) {
return xScale(i);
})
.attr("y", function(d) {
return h - yScale(d.y0) - yScale(d.y);
})
.attr("height", function(d) {
return yScale(d.y);
})
.attr("width", xScale.rangeBand())
.attr("class", "rectbar");
}
Edited to fix a small bug, updating the asd selection's data.
I made 2 simple but crucial changes to your code.
https://jsfiddle.net/guanzo/510ep9ux/6/
From
gs = svg.selectAll("g").data(stack_data);
to
gs = svg.selectAll("g.stacked_bars").data(stack_data);
The axis is also contained in a g element, so you have to ensure you're only selecting elements that are used for your data, and not unrelated elements.
From
gs.append("g")
.attr("class", "axis")
.attr("transform", "translate(0," + (h - padding) + ")")
.call(xAxis);
to
svg.append("g")
.attr("class", "axis")
.attr("transform", "translate(0," + (h - padding) + ")")
.call(xAxis);
If you go into the browser inspector you'll see that you have an axis element for EVERY stacked_bars element, you only need 1 obviously. It only looks like there's 1 axis because they're absolutely positioned and stacked on top of each other.
I changed it so that the axis is appended when the svg is created, and every time new data is selected, the axis will update itself.
I'm trying to make a singular column for a bar graph in d3.js, the purpose of which is to bar-graph the coefficients of the other line graph in my program. I'm familiar with how they are made when the data is in .csv format, but in this case right now I'm trying to make it from three variables. The three variables are:
var xtwo;
var xone;
var xzero;
which have values put into them in a later part. I've built a skeleton based on what I know and have seen, which is right here:
//Bar Graph
var barmargin = {
top: 20,
right: 20,
bottom: 30,
left: 60
},
barwidth = 500 - barmargin.left - barmargin.right,
barheight = 350 - barmargin.top - barmargin.bottom;
//X scale
var barx = d3.scale.ordinal()
.rangeRoundBands([0, barwidth], .1);
//Y scale
var bary = d3.scale.linear()
.rangeRound([barheight, 0]);
//bar graph colors
var color = d3.scale.ordinal()
.range(["#FF5C33", "#F48C00", "#FFFF5C"]);
// Use X scale to set a bottom axis
var barxAxis = d3.svg.axis()
.scale(barx)
.orient("bottom");
// Same for y
var baryAxis = d3.svg.axis()
.scale(bary)
.orient("left")
.tickFormat(d3.format(".2s"));
// Addchart to the #chart div
var svg = d3.select("#chart").append("svg")
.attr("width", barwidth + barmargin.left + barmargin.right)
.attr("height", barheight + barmargin.top + barmargin.bottom)
.append("g")
.attr("transform", "translate(" + barmargin.left + "," + barmargin.top + ")");
//Where data sorting happens normally
var bardata.data([xzero, xone, xtwo]);
//Y domain is from zero to 5
y.domain([0, 5]);
svg.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + barheight + ")")
.call(barxAxis);
svg.append("g")
.attr("class", "y axis")
.call(baryAxis);
bardata.selectAll("rect")
.data(function(d) {
return d.types;
})
.enter().append("rect")
.attr("width", barx.rangeBand())
.attr("y", function(d) {
return bary(d.y1);
})
.attr("height", function(d) {
return bary(d.y0) - bary(d.y1);
})
.style("fill", function(d) {
return color(d.name);
});
but I can't really figure out how to make it work correctly. I thought that I could manually make the .data but it seems to not be working that way.
Full code if necessary: https://jsfiddle.net/tqj5maza/1/
Broadly speaking: you want to create three bars, sat on top of each other, from three different values. The three values will be enough to scale the bars, but they in themselves won't be enough to position the bars- each bar needs to be offset by the size of the bars that have gone before.
d3 can only read the values that are already in the data you send it- you can't really access the previous values as you go, as each datum is bound to a separate element. Thus, what you need to do is to create some new data, which has all the numbers required to display it.
Here's one way that you might do that:
var canvas = d3.select("#canvas").append("svg").attr({width: 400, height: 400})
var values = [50, 90, 30]
var colours = ['#FA0', '#0AF', '#AF0']
var data = []
var yOffset = 0
//Process the data
for(var i = 0; i < values.length; i++) {
var datum = {
value : values[i],
colour : colours[i],
x: 0,
y: yOffset
}
yOffset += values[i]
data.push(datum)
}
var bars = canvas.selectAll('rect').data(data)
bars
.enter()
.append('rect')
.attr({
width : 30,
height : function(d) {
return d.value
},
y : function(d) {
return d.y //
}
})
.style({
fill : function(d) {
return d.colour
}
})
http://jsfiddle.net/r3sazt7m/
d3's layout functions all do more or less this- you pass them a set of data, and they return new data containing the values that the SVG drawing instructions require.
I have been experimenting with D3 for some time now, but i have come to a dead end.
On initialization i am creating an svg with the axes set on some default data.
Graph.initiateGraph = function(data){
Graph.time_extent = d3.extent(data, function(d) { return d.date; });
Graph.time_scale = d3.time.scale()
.domain(Graph.time_extent)
.range([Graph.padding, Graph.w]);
Graph.value_extent = d3.extent(data, function(d) { return parseInt(d.value); });
Graph.value_scale = d3.scale.linear()
.domain(Graph.value_extent)
.range([Graph.h, Graph.padding]);
Graph.svg = d3.select("#graph")
.append("svg:svg")
.attr("width", Graph.w + Graph.padding)
.attr("height", Graph.h + Graph.padding)
.call(d3.behavior.zoom().x(Graph.time_scale).y(Graph.value_scale).on("zoom", Graph.zoom));
Graph.chart = Graph.svg.append("g")
.attr("class","chart")
.attr("pointer-events", "all")
.attr("clip-path", "url(#clip)");
Graph.line = d3.svg.line()
.x(function(d){ return Graph.time_scale(d.date); })
.y(function(d){ return Graph.value_scale(d.value); })
.interpolate("linear");
Graph.time_axis = d3.svg.axis()
.scale(Graph.time_scale)
.orient("bottom").ticks(5);
Graph.value_axis = d3.svg.axis()
.scale(Graph.value_scale)
.orient("left").ticks(5);
Graph.svg.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + Graph.h + ")")
.call(Graph.time_axis);
Graph.svg.append("g")
.attr("class","y axis")
.attr("transform","translate(" + Graph.padding + ",0)")
.call(Graph.value_axis);
}
Then, i have a pair of input boxes that implement jquery calendar script to provide 2 dates (start and end). I then update my svg chart with these dates.
$("#date_filter_button").click(function(){
var start_date = $("#analysis [name='date_start']").datepicker('getDate');
var end_date = $("#analysis [name='date_end']").datepicker('getDate');
Graph.time_extent = [start_date.getTime(),end_date.getTime()];
Graph.time_scale.domain(Graph.time_extent);
Graph.svg.select(".x.axis").transition().call(Graph.time_axis);
}
Unit here everything works like a charm. The x axis domain changes to the dates provided. So then i draw the chart and it works beautifully.
The problem comes when i try to pan/zoom the chart. On the first pan/zoom, the time axis changes to the first default values i used on the initialization.
Graph.zoom = function(){
var trans = d3.event.translate[0],
scale = d3.event.scale;
Graph.svg.select(".x.axis").call(Graph.time_axis);
Graph.svg.select(".y.axis").call(Graph.value_axis);
}
It's like when the zoom function comes in and calls the Graph.time-axis, it uses the initial values of the Graph.time_extent and/or Graph.time_scale values...