Reputation: 2735
I have a project where I need to zoom on 3 axes independently. I'm using scroll bars to accomplish this, but the axes aren't redrawing when the zoom happens.
Additionally, the clip path doesn't seem to be working as expected.
Eventually I want to add panning functionality to the chart as well, but I'm not sure where to start for this.
Thanks in advance for the help.
// cases vs deaths of a disease over time
var data = [
{"year": "1960", "cases":"887", "deaths": "199"},
{"year": "1965", "cases":"218", "deaths": "55"},
{"year": "1993", "cases":"37046", "deaths": "931"},
{"year": "1994", "cases":"38735", "deaths": "118"},
{"year": "1995", "cases":"19903", "deaths": "624"},
{"year": "1997", "cases":"4170", "deaths": "125"},
{"year": "1998", "cases":"10000", "deaths": "0"}
];
data.forEach(function (d) {
d.year = d3.time.format("%Y").parse(d.year.toString());
d.cases = +d.cases;
d.deaths = +d.deaths;
});
var margin = { top: 30, right: 40, bottom: 30, left: 50 },
width = 500 - margin.left - margin.right,
height = 270 - margin.top - margin.bottom;
var xScale = d3.time.scale()
.domain(d3.extent(data, function (d) { return d.year; }))
.range([0, width]);
var yScaleLeft = d3.scale.linear()
.domain([0, d3.max(data, function (d) { return d.cases; })])
.range([height, 0]);
var yScaleRight = d3.scale.linear()
.domain([0, d3.max(data, function (d) { return d.deaths; })])
.range([height, 0]);
var xAxis = d3.svg.axis()
.scale(xScale)
.orient("bottom").ticks(5);
var yAxisLeft = d3.svg.axis()
.scale(yScaleLeft)
.orient("left").ticks(5);
var yAxisRight = d3.svg.axis()
.scale(yScaleRight)
.orient("right").ticks(5);
var lineCases = d3.svg.line()
.x(function (d) { return xScale(d.year); })
.y(function (d) { return yScaleLeft(d.cases); });
var lineDeaths = d3.svg.line()
.x(function (d) { return xScale(d.year); })
.y(function (d) { return yScaleRight(d.deaths); });
var svg = d3.select("#chart").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")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(xAxis);
svg.append("g")
.attr("class", "y axis yleft")
.call(yAxisLeft);
svg.append("g")
.attr("class", "y axis yright")
.call(yAxisRight)
.attr('transform', 'translate(' + width + ',0)');
svg.append("path")
.datum(data)
.attr("class", "line lineLeft")
.style("stroke", "red")
.attr("d", lineCases(data))
.attr("clip", "url(#clip)");
svg.append("path")
.datum(data)
.attr("class", "line lineRight")
.attr("d", lineDeaths(data))
.attr("clip", "url(#clip)");
svg.append("clipPath")
.attr("id", "clip")
.append("rect")
.attr("width", width)
.attr("height", height);
$("#slider-x").slider({
orientation: "horizontal",
range: "min",
min: 1000,
max: 10000, // make max be (maxDate-minDate).Days*1000, so you can zoom to one day
value: 1000,
slide: function( event, ui ) {
zoomXWithSlider(ui.value/1000);
}
});
$( "#slider-y-left" ).slider({
orientation: "vertical",
range: "min",
min: 1000,
max: 10000,
value: 1000,
slide: function( event, ui ) {
zoomLeftWithSlider(ui.value/1000);
}
});
$("#slider-y-right").slider({
orientation: "vertical",
range: "min",
min: 1000,
max: 10000,
value: 1000,
slide: function( event, ui ) {
zoomRightWithSlider(ui.value/1000);
}
});
function zoomXWithSlider(scale) {
// Note: works only on the <g> element and not on the <svg> element
// which is a common mistake
svg.selectAll("path.line").attr("transform", "scale("+scale+", 1)");
svg.select(".x.axis").call(xAxis);
}
function zoomLeftWithSlider(scale) {
svg.select("path.line.lineLeft").attr("transform", "scale(1, "+scale+")");
svg.select(".y.axis.yleft").call(yAxisLeft);
}
function zoomRightWithSlider(scale) {
svg.select("path.line.lineRight").attr("transform", "scale(1, "+scale+")");
svg.select(".y.axis.yright").call(yAxisRight);
}
Upvotes: 1
Views: 1905
Reputation: 2735
var zoom = d3.behavior.zoom() //zoomYAxis
.x(xScale)
.y(yScaleLeft)
.on("zoom", function(){
// don't let double-click or scroll wheel do anything
if (d3.event.sourceEvent == null || d3.event.sourceEvent.type == "wheel"){
zoom.scale(previousScale);
zoom.translate(previousTranslate);
zoomRight.scale(previousScale);
zoomRight.translate(previousTranslate);
return;
}
// set previous scale for future use
previousScale = zoom.scale();
previousTranslate = zoom.translate();
//zoom.translate(panLimit());
//zoomRight.translate(zoom.translate());
// update the right side scale
zoomRight.scale(previousScale);
zoomRight.translate(previousTranslate);
// redraw lines
svg.select("path.line.lineLeft").attr("d", lineCases(data));
svg.select("path.line.lineRight").attr("d", lineDeaths(data));
// redraw axes
svg.select(".x.axis").call(xAxis);
svg.select(".y.axis.yleft").call(yAxisLeft);
svg.select(".y.axis.yright").call(yAxisRight);
});
I eventually got this working. I don't need the clip-path to work in the jsfiddle because it works in our actual project. Additionally, I didn't end up limiting the pan functionality because it got very complex with the math. So I just put a reset button on it.
Upvotes: 2