Reputation: 63
The JSFiddle of my code is at this URL http://jsfiddle.net/b8eLJ/1/
Within the code, I have implemented a back button. The objective is that the calendar on x-axis should go back in time. As this happens, the lines should also move back in time.
I have the x-axis working correctly with the new domain - but am struggling with the lines and circles.
I have also looked at the following example http://bl.ocks.org/mbostock/1166403
I am a little confused about how to either "select the line and move it" or "destroy the line and recreate it". I have tried both and neither seem to work.
function startFunction() {
console.log("start");
endDate.setDate(endDate.getDate() - 7);
startDate.setDate(startDate.getDate() - 7);
//change the domain to reflect the new dates
xScale.domain([startDate, endDate]);
var t = svg.transition().duration(750);
t.select(".x.axis").call(xAxis);
//???
var pl = svg.selectAll("path.line");
pl.exit().remove();
}
// INPUT
dataset2 = [{
movie: "test",
results: [{
week: "20140102",
revenue: "5"
}, {
week: "20140109",
revenue: "10"
}, {
week: "20140116",
revenue: "17"
}, ]
}, {
movie: "test",
results: [{
week: "20140206",
revenue: "31"
}, {
week: "20140213",
revenue: "42"
}]
}];
console.log("1");
var parseDate = d3.time.format("%Y%m%d").parse;
var lineFunction = d3.svg.line()
.x(function (d) {
return xScale(parseDate(String(d.week)));
})
.y(function (d) {
return yScale(d.revenue);
})
.interpolate("linear");
console.log("2");
var endDate = new Date();
var startDate = new Date();
startDate.setDate(startDate.getDate() - 84);
//SVG Width and height
var margin = {
top: 20,
right: 10,
bottom: 20,
left: 40
};
var w = 750 - margin.left - margin.right;
var h = 250 - margin.top - margin.bottom;
//X SCALE AND AXIS STUFF
//var xMin = 0;
//var xMax = 1000;
var xScale = d3.time.scale()
.domain([startDate, endDate])
.range([0, w]);
console.log(parseDate("20130101"));
console.log("3");
var xAxis = d3.svg.axis()
.scale(xScale)
.orient("bottom")
.ticks(12);
console.log("4S");
//Y SCALE AND AXIS STUFF
//max and min test
var minY = d3.min(dataset2, function (kv) {
return d3.min(kv.results, function (d) {
return +d.revenue;
})
});
var maxY = d3.max(dataset2, function (kv) {
return d3.max(kv.results, function (d) {
return +d.revenue;
})
});
console.log("min y " + minY);
console.log("max y " + maxY);
var yScale = d3.scale.linear()
.domain([minY, maxY])
.range([h, 0]);
var yAxis = d3.svg.axis()
.scale(yScale)
.orient("left")
.ticks(10);
//Create SVG element
var svg = d3.select("body")
.append("svg")
.attr("width", w + margin.left + margin.right)
.attr("height", h + margin.top + margin.bottom)
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
console.log("4S1");
//CREATE X-AXIS
svg.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + (h) + ")")
.call(xAxis);
//Create Y axis
svg.append("g")
.attr("class", "y axis")
.attr("transform", "translate(,0)")
.call(yAxis);
//create circle
var movie_groups = svg.selectAll("g.metric_group")
.data(dataset2).enter()
.append("g")
.attr("class", "metric_group");
var circles = movie_groups.selectAll("circle")
.data(function (d) {
return d.results;
});
svg.selectAll("g.circle")
.data(dataset2)
.enter()
.append("g")
.attr("class", "circle")
.selectAll("circle")
.data(function (d) {
return d.results;
})
.enter()
.append("circle")
.attr("cx", function (d) {
// console.log(d[0]);
console.log(parseDate(d.week));
return xScale(parseDate(d.week));
})
.attr("cy", function (d) {
return yScale(d.revenue);
})
.attr("r", 3);
//create line
//create line
var lineGraph = svg.selectAll("path.line")
.data(dataset2).enter().append("path")
.attr("d", function (d) {
return lineFunction(d.results);
})
.attr("class", "line");
Upvotes: 1
Views: 1052
Reputation: 5015
To clarify, lines moving back in time will actually translate to lines moving forward to the right since their date is not changing and the time axis is moving to the right. I hope I am thinking clear here...it is late.
Importantly, your data is not changing between clicks so there will be no new data to be bound in the enter() selection after the initial call. Lines will be drawn once and only once.
Since your axis is the movable part, one quick solution would be to keep removing the lines and rebuilding them again inside startFunction
, like this:
var lineGraph = svg.selectAll("path.line").remove();
lineGraph = svg.selectAll("path.line")
.data(dataset2);
I tried this and it works. Note however that I am not removing the lines off of the exit selection and thus not truly leveraging the EUE pattern (Enter/Update/Exit). But, since your data is not really changing, I am not sure what you could add to it between clicks that could be used as the key to selection.data. I hope this helps...
NOTE: I am not particularly fond of this solution and considered writing it as a comment but there is too much verbiage. For one thing, object constancy is lost since we veered away from the EUE pattern and the "graph movement" is ugly. This can be mitigated some by adding a transition delay in the drawing of lines (path) as shown below...but still...
lineGraph.enter().append("path").transition().delay(750)
.attr("d", function (d) {
return lineFunction(d.results);
})
Upvotes: 1