Zmodyfikowałem mbostock's drag+zoom example, aby uzyskać szybkość zbliżenia 4x i umieścić ją w jsfiddle. Wyjaśniłem moje myślenie poniżej. To jest moja pierwsza próba odpowiedzi na przepełnienie stosu, proszę bądź miły.
Jak wyjaśniono w odpowiedzi Raúla Martína, można użyć wzoru w ramach funkcji redraw()
, aby zmienić współczynnik powiększenia. Musisz wykonać dodatkowe czynności, aby upewnić się, że zachowanie d3 nadal działa poprawnie ze zmodyfikowaną stopą powiększenia.
powiększenia wyśrodkowany na wybranym miejscu (na przykład kursor)
Poprzez zachowanie domyślne d3 skupia powiększenie na wskaźnik myszy, np jeśli masz wskaźnik myszy w lewym górnym rogu obrazu, przybliża się on w lewym górnym rogu, a nie w środku obrazu. Aby uzyskać ten efekt, skaluje obraz, a następnie zmienia translację obrazu tak, aby punkt pod kursorem myszy pozostawał w tym samym miejscu na ekranie. Z tego powodu wartość zoom.translate()
zmienia się po przewinięciu koła myszy, nawet jeśli obraz nie wygląda tak, jak porusza się po ekranie.
Po zmianie prędkości powiększenia wartości d3 zoom.translate()
nie są poprawne. Wypracować prawidłowe tłumaczenie trzeba znać następujące informacje (ignorowania wartości liczbowe):
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
formuła wypracować new_translate
zastosować do obrazu jest wówczas:
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;
You można zastosować to do obrazu wraz z nową skalę z:
svg.attr("transform", "translate(" + new_translate + ")scale(" + new_scale + ")");
będziesz wtedy musiał aktualizować prev_scale = new_scale
i prev_translate = new_translate
gotowy do następna iteracja redraw()
Pan bez skalowania zachowanie powiększenia
D3 pozwala na patelni bez skalowania, klikając i przeciągając. Jeśli klikniesz i przeciągniesz, zoom.scale()
pozostanie niezmienione, ale zmiany zostaną zmienione na zoom.translate()
. Nowa wartość zoom.translate()
jest nadal poprawna nawet po zmianie prędkości powiększenia. Musisz jednak wiedzieć, kiedy użyć tej wartości: zoom.translate()
i kiedy użyć wartości translate, którą obliczysz, aby powiększyć punkt środkowy.
Możesz sprawdzić, czy patelnia lub zoom działa, sprawdzając, czy prev_scale
to to samo, co . Jeśli te dwie wartości są identyczne, wiesz, że ma miejsce patelnia i możesz użyć new_translate = zoom.translate()
, aby przesunąć obraz. W przeciwnym razie wiesz, że ma miejsce powiększenie i możesz obliczyć wartość new_translate
zgodnie z powyższym opisem. Robię to, dodając funkcję do zdarzenia 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 + ")");
}
wymyśliłeś to? – kishanio
@kishanio Zaproponowałem rozwiązanie –