grafico d3 con zoom limitato

Ho implementato un grafico di linea d3 che legge i dati da un file CSV e poi traccia più righe che reagiscono agli events del mouseover. Funziona bene con pan e zoom utilizzando il seguente codice (mi dispiace che sia così lungo e leggermente disordinato, ma ho ritenuto che fosse meglio visualizzare il codice completo):

d3.csv("ijisb.csv", function(error, data) { var margin = {top: 50, right: 120, bottom: 50, left: 70}, width = 1200 - margin.left - margin.right, height = 800 - margin.top - margin.bottom; var parseDate = d3.time.format("%m%d").parse; var color = d3.scale.category20(); color.domain(d3.keys(data[0]).filter(function(key) { return key !== "date"; })); data.forEach(function(d) { d.date = parseDate(d.date); }); var sources = color.domain().map(function(name) { return { name: name, values: data.map(function(d) { return {date: d.date, temperature: +d[name]}; }) }; }); var x = d3.time.scale() .range([0, width]) .domain([ d3.min(data, function(d) { return d.date; }), d3.max(data, function(d) { return d.date; }) ]); var y = d3.scale.linear() .range([height, 0]) .domain([ 0, d3.max(sources, function(c) { return d3.max(c.values, function(v) { return v.temperature; }); }) ]); var xAxis = d3.svg.axis() .scale(x) .orient("bottom") .ticks(12) .tickFormat(d3.time.format("%b %d")); var yAxis = d3.svg.axis() .scale(y) .orient("left") .ticks(5); var line = d3.svg.line() .defined(function(d) { return d.temperature >= 0; }) .x(function(d) { return x(d.date); }) .y(function(d) { return y(d.temperature); }); var zoom = d3.behavior.zoom() .x(x) .y(y) .scaleExtent([1, 8]) .on("zoom", zoomed); var svg = d3.select("body").append("svg") .attr("width", "100%") .attr("height", "100%") .attr("viewBox", "0 0 1200 800") .append("g") .attr("transform", "translate(" + margin.left + "," + margin.top + ")") .call(zoom); var rect = svg.append("svg:rect") .attr("width", width) .attr("height", height) .attr("class", "plot"); var make_x_axis = function () { return d3.svg.axis() .scale(x) .orient("bottom") .ticks(12) .tickFormat(d3.time.format("%b %d")); }; var make_y_axis = function () { return d3.svg.axis() .scale(y) .orient("left") .ticks(5); }; svg.append("g") .attr("class", "x axis") .attr("transform", "translate(0," + height + ")") .call(xAxis); svg.append("g") .attr("class", "y axis") .call(yAxis); svg.append("g") .attr("class", "x grid") .attr("transform", "translate(0," + height + ")") .call(make_x_axis() .tickSize(-height, 0, 0) .tickFormat("")); svg.append("g") .attr("class", "y grid") .call(make_y_axis() .tickSize(-width, 0, 0) .tickFormat("")); var source = svg.selectAll(".source") .data(sources) .enter().append("g") .attr("class", "source"); var clip = svg.append("clipPath") .attr("id", "clip") .append("rect") .attr("x", 0) .attr("y", 0) .attr("width", width) .attr("height", height) .append("text"); source.append("path") .data(sources) .attr("class", "line") .attr("clip-path", "url(#clip)") .attr("d", function(d) { return line(d.values); }) .style("stroke", function(d) {return color(d.name);}) .style("opacity", 0.8) .on("mouseover", function(d){ d3.select(this) .style("stroke",function(d) {return color(d.name);}) .style("opacity", 1.0) .style("stroke-width", 2.5); this.parentNode.parentNode.appendChild(this.parentNode); d3.select('#text-' + d.name) .style("fill",function(d) {return color(d.name);}) .style("font-weight", 700); }) .on("mouseout", function(d) { d3.select(this) .transition() .duration(250) .style("stroke", function(d) {return color(d.name);}) .style("stroke-width", 1.5) .style("opacity", 0.8); d3.select('#text-' + d.name) .transition() .duration(250) .style("fill", function(d) {return color(d.name);}) .style("font-weight", 400); }) .attr("id", function(d, i) { return "path-" + d.name; }); source.append("text") .datum(function(d) { return {name: d.name}; }) .attr("x", function(d, i) { return width+10; }) .attr("y", function(d, i) { return (i*(height/16)); }) .style("fill", function(d) {return color(d.name);}) .on("mouseover", function(d){ d3.select('#path-' + d.name) .style("stroke",function(d) {return color(d.name);}) .style("opacity", 1.0) .style("stroke-width", 2.5); this.parentNode.parentNode.appendChild(this.parentNode); d3.select(this) .style("fill",function(d) {return color(d.name);}) .style("font-weight", 700); }) .on("mouseout", function(d) { d3.select('#path-' + d.name) .transition() .duration(250) .style("stroke", function(d) {return color(d.name);}) .style("stroke-width", 1.5) .style("opacity", 0.8); d3.select(this) .transition() .duration(250) .style("fill", function(d) {return color(d.name);}) .style("font-weight", 400); }) .text(function(d) { return d.name; }) .attr("font-family","sans-serif") .attr("font-size","14px") .attr("id", function(d, i) { return "text-" + d.name; } ); var minT = new Date('01/01/1900'), maxT = new Date('01/01/2002'), w = $(window).width(); function zoomed() { d3.event.translate; d3.event.scale; 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("")); source.select(".line") .attr("d", function(d) { return line(d.values); }) .style("stroke", function(d) {return color(d.name);}); } }); 

Il problema che ho è che voglio limitare la panoramica e lo zoom in modo che non sia ansible ingrandire o spostare il grafico sullo schermo. Posso farlo impostando la scalaExtent sullo zoom (implementato nell'esempio precedente) e cambiando la function zoomata su:

  function zoomed() { var t = zoom.translate(), tx = t[0]; ty = t[1]; tx = Math.min(tx, 0); zoom.translate([tx, ty]); d3.event.translate; d3.event.scale; 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("")); source.select(".line") .attr("d", function(d) { return line(d.values); }) .style("stroke", function(d) {return color(d.name);}); } 

Questo limita l'asse x più basso a zero. Tuttavia difficile provo, tuttavia, non posso limitare il valore massimo dell'asse x, il che significa che il grafico può ancora penzolare troppo in alto a destra.

Qualsiasi aiuto? Spero che questo ha senso!

tacca

Grazie per l'aiuto, lo ho fatto con il seguente codice alla fine:

 var t = zoom.translate(), s = zoom.scale(); tx = Math.min(0, Math.max(width * (1 - s), t[0])); ty = Math.min(0, Math.max(height * (1 - s), t[1])); zoom.translate([tx, ty]); 

La difficoltà era di limitare il grafico a diversi livelli di zoom, che ora risolve. Le dichiarazioni d3.event.translate e d3.event.scale furono anche inutili e dovrebbero essere state rimosse.

È ansible controllare manualmente il valore e ripristinarlo se è troppo alto:

 if(tx > threshold) { tx = threshold; } 

Inoltre, le affermazioni

 d3.event.translate; d3.event.scale; 

nel codice non hanno alcun effetto.