Ho modificato lo drag+zoom example di mbostock per avere una velocità di zoom 4x e inserirla in un jsfiddle. Ho spiegato il mio pensiero qui sotto. Questo è il mio primo tentativo di una risposta di overflow dello stack, per favore sii gentile.
Come spiegato nella risposta di Raúl Martín, è possibile utilizzare una formula all'interno della funzione redraw()
per modificare la velocità dello zoom. È necessario eseguire alcuni passaggi aggiuntivi per assicurarsi che il comportamento di d3 funzioni ancora correttamente con la velocità di zoom modificata.
Zoom centrata su un punto scelto (ad esempio cursore)
Per comportamento predefinito d3 concentra lo zoom il puntatore del mouse, ad esempio se hai il puntatore del mouse nella parte in alto a sinistra dell'immagine, ingrandisce in alto a sinistra anziché al centro dell'immagine. Per ottenere questo effetto, ridimensiona l'immagine e quindi cambia anche la traduzione dell'immagine in modo che il punto sotto il cursore del mouse rimanga nella stessa posizione sullo schermo. Questo è il motivo per cui il valore di zoom.translate()
cambia quando si fa scorrere la rotellina del mouse anche se l'immagine non sembra spostarsi sullo schermo.
Se si modifica la velocità dello zoom, i valori di d3 zoom.translate()
non sono più corretti. Per calcolare la traduzione corretta è necessario conoscere le seguenti informazioni (ignorare i valori numerici):
var prev_translate = [100,100] // x, y translation of the image in last redraw
var prev_scale = 0.1 // Scale applied to the image last redraw
var new_scale = 0.4 // The new scale being applied
var zoom_cp = [150, 150] // The zoom "center point" e.g. mouse pointer
La formula per calcolare il new_translate
da applicare all'immagine viene poi:
new_translate[0] = zoom_cp[0] - (zoom_cp[0] - prev_translate[0])
* new_scale/prev_scale;
new_translate[1] = zoom_cp[1] - (zoom_cp[1] - prev_translate[1])
* new_scale/prev_scale;
È può applicare questo all'immagine con il vostro nuova scala con:
svg.attr("transform", "translate(" + new_translate + ")scale(" + new_scale + ")");
Avrai quindi aggiornare prev_scale = new_scale
e prev_translate = new_translate
pronto per la prossima iterazione del redraw()
Pan senza ridimensionamento comportamento zoom
la D3 permette di padella senza ridimensionamento cliccando e trascinando. Se si fa clic e si trascina, quindi zoom.scale()
rimane lo stesso ma le modifiche zoom.translate()
. Il nuovo valore zoom.translate()
è ancora corretto anche dopo aver modificato la velocità dello zoom. Tuttavia, è necessario sapere quando utilizzare questo valore zoom.translate()
e quando utilizzare il valore di traduzione calcolato per lo zoom su un punto centrale.
È possibile determinare se una panoramica o uno zoom si verificano osservando se prev_scale
corrisponde a new scale
. Se i due valori sono identici, sai che è in corso una panoramica e puoi utilizzare new_translate = zoom.translate()
per spostare l'immagine. Altrimenti, sai che è in corso uno zoom ed è possibile calcolare il valore new_translate
come descritto sopra. Lo faccio aggiungendo una funzione all'evento zoomstart
.
var zoom_type = "?";
var scale_grad = 4; // Zoom speed multiple
var intercept = 1 * (1 - scale_grad)
var svg = d3.select("body").append("svg:svg")
.attr("width", 1000)
.attr("height", 2000)
.append("svg:g")
.call(d3.behavior.zoom()
.on("zoom", redraw)
.on("zoomstart", zoomstarted))
.append("svg:g");
function zoomstarted() {
zoom_type = "?";
}
function redraw() {
var scale = d3.event.scale;
// Use a linear scale, don't let it go below the minimum scale
// extent
var new_scale = Math.max(scale_grad * scale + intercept,
scale_extent[0]);
// If hit the minimum scale extent then stop d3 zoom from
// going any further
if (new_scale == scale_extent[0]) {
zoom.scale((scale_extent[0] - intercept)/scale_grad);
}
// Set up zoom_type if have just started
// If the scale hasn't changed then a pure translation is
// taking place, otherwise it is a scale
if (zoom_type == "?") {
if (new_scale == prev_scale) {
zoom_type = "translate"
} else {
zoom_type = "scale"
}
}
// zoom_cp is the static point during the zoom, set as
// mouse pointer position (you need to define a listener to track)
var new_translate = [0, 0];
zoom_cp = [mouse_x, mouse_y];
// If the event is a translate just apply d3 translate
// Otherwise calculate what translation is required to
// keep the zoom center point static
if (zoom_type == "translate") {
new_translate = d3.event.translate
} else if (zoom_type == "scale") {
new_translate[0] = zoom_cp[0]
- (zoom_cp[0] - prev_translate[0]) * new_scale/prev_scale;
new_translate[1] = zoom_cp[1]
- (zoom_cp[1] - prev_translate[1]) * new_scale/prev_scale;
}
// Update the variables that track the last iteration of the
// zoom
prev_translate = new_translate;
prev_scale = new_scale;
zoom.translate(new_translate);
// Apply scale and translate behaviour
svg.attr("transform", "translate(" + new_translate +
")scale(" + new_scale + ")");
}
hai capito? – kishanio
@kishanio Ho proposto una soluzione –