I've been at this for a few days now and I can't get this chart to obey panning bounds. Initially, the data could be pulled off the page both negatively and positively, but I've been able to stop the negative by following this blog post. I'll paste what I believe is the relevant code here, but the file is way to long to include.
The chart in question is an elevation chart made up of concatenated area objects that are colored according to their gradient.
There's a commented out line that is the one giving trouble. I've put question marks in place of what is supposed to be a max bound. For some reason, I can't find the max bound of the data area.
Here's a Plunkr
// Set up the size of the chart relative to the div
var x = d3.scale.linear().range([0, (width-80)]);
var y = d3.scale.linear().range([height, 0]);
var y1 = d3.scale.linear().range([height, 0]);
// Define the look of the axis
var xAxis = d3.svg.axis().scale(x).orient("bottom").ticks(5);
var yAxis = d3.svg.axis().scale(y).orient("left").ticks(5);
var yAxisRight = d3.svg.axis().scale(y1).orient("left").ticks(5);
// Areas are segments of the chart filled with color
var area = d3.svg.area()
.x(function(d) { return x(d.distance); })
.y0(height)
.y1(function(d) { return y(d.elevation); });
// Functions for handling zoom events
var gradientZoomListener = d3.behavior.zoom()
.scaleExtent([1, 10])
.on("zoom", gradientZoomHandler);
function gradientZoomHandler() {
var t = gradientZoomListener.translate(),
tx = t[0],
ty = t[1];
tx = Math.min(tx, 0);
// tx = Math.max(tx, ??);
gradientZoomListener.translate([tx,ty])
gradientChart.select(".x.axis").call(xAxis);
gradientChart.select(".y.axis").call(yAxis);
gradientChart.selectAll('.area').attr('d', area);
}