Erstellen Sie einen Panning-Effekt für SVG

0
23

Früher in diesem Monat auf die Animation bei der Arbeit Locker, wir hatten eine Diskussion über die Suche nach einem Weg, um Benutzern das schwenken innerhalb einer SVG.

Ich habe diese demo unten, um zu zeigen, wie ich diesen Ansatz in Frage:

Finden Sie den Stift, Demo – SVG-Panning-von Louis Hoebregts (@Mamboleoo) auf CodePen.

Hier sind die vier Schritte, um die oben genannten demo-Arbeit:

  1. Holen Sie sich Maus-und touch-events vom Benutzer
  2. Berechnen Sie die Maus offsets von seiner Herkunft
  3. Speichern Sie die neue viewBox-Koordinaten
  4. Bearbeitung dynamischer viewport

Lassen Sie uns diese Schritte einen nach dem anderen gründlich.

1. Maus & Touch-Ereignisse

Um die Maus oder berühren Sie die position, wir müssen zuerst zum hinzufügen von Ereignis-Listenern auf unseren SVG. Wir können den Zeiger verwenden, Ereignisse zu verarbeiten alle Art von Zeiger (Maus/touch/stylus/…) aber diese Ereignisse sind noch nicht von allen Browsern unterstützt. Wir müssen hinzufügen einige fallback-um sicherzustellen, dass alle Benutzer werden in der Lage zu ziehen die SVG.

// Wir wählen die SVG in die Seite
var svg = document.querySelector(‘svg’);

// Wenn browser pointer-events
wenn (Fenster.PointerEvent) {
svg.addEventListener(‘pointerdown’, onPointerDown); // Zeiger gedrückt wird
svg.addEventListener(‘pointerup’, onPointerUp); // Freigeben des Zeigers
svg.addEventListener(‘pointerleave’, onPointerUp); // Zeiger wird aus dem SVG-Bereich
svg.addEventListener(‘pointermove’, onPointerMove); // Zeiger bewegt
} else {
// Fügen Sie alle Maus-Ereignisse Listener-fallback
svg.addEventListener(‘mousedown’, onPointerDown); // Drücken Sie die Maus
svg.addEventListener(‘mouseup’, onPointerUp); // Loslassen der Maus
svg.addEventListener(‘mouseleave’, onPointerUp); // Maus wird aus dem SVG-Bereich
svg.addEventListener(‘mousemove’, onPointerMove); // Maus bewegen

// Fügen Sie alle touch-Ereignisse Listener-fallback
svg.addEventListener(‘touchstart’, onPointerDown); // Finger den Touchscreen berührt
svg.addEventListener(‘touchend’, onPointerUp); // Finger nicht mehr den Bildschirm berühren
svg.addEventListener(‘touchmove’, onPointerMove); // Finger bewegen
}

Da hätten wir touch-events und pointer-events, brauchen wir eine kleine Funktion, um zurück auf die Koordinaten entweder aus dem ersten finger, entweder aus einem Zeiger.

// Diese Funktion gibt ein Objekt mit X – & Y-Werte aus der pointer-event
Funktion getPointFromEvent (event) {
var Punkt = {x:0, y:0};
// Wenn das Ereignis ausgelöst wird, durch ein touch-event, bekommen wir die position des ersten Fingers
if (event.targetTouches) {
Punkt.x = event.targetTouches[0].clientX;
Punkt.y = event.targetTouches[0].clientY;
} else {
Punkt.x = event.clientX;
Punkt.y = event.clientY;
}

return point;
}

Sobald die Seite fertig ist und wartet für alle Benutzer-Interaktionen, können wir anfangen, Umgang mit dem mousedown/touchstart events zu speichern, die original-Koordinaten des Zeigers an und erstellen Sie eine variable, um uns wissen zu lassen, wenn der Zeiger unten ist, oder nicht.

// Diese variable wird verwendet, später für das verschieben von Ereignissen zu überprüfen, ob Zeiger unten ist, oder nicht
var isPointerDown = false;

// Diese variable enthält die original-Koordinaten, wenn der Benutzer starten Sie die Maus oder berühren Sie den Bildschirm
var pointerOrigin = {
x: 0,
y: 0
};

// Funktion, die aufgerufen wird, die von der Ereignis-Listener, wenn der Benutzer die start drücken/berühren
Funktion onPointerDown(event) {
isPointerDown = true; // Wir setzen den Mauszeiger als nach unten

// Holen wir uns die position des Mauszeigers beim klicken/touchdown, so können wir den Wert abrufen, sobald der Benutzer beginnt, ziehen
var pointerPosition = getPointFromEvent(event);
pointerOrigin.x = pointerPosition.x;
pointerOrigin.y = pointerPosition.y;
}

2. Berechnen Sie Die Maus Offsets

Nun, wir haben die Koordinaten der ursprünglichen position, wo der Benutzer gestartet hat, ziehen Sie innerhalb des SVG -, können wir berechnen Sie die Entfernung zwischen der aktuellen Mauszeiger-position und seine Herkunft. Wir tun dies sowohl für die X-und Y-Achse, und wir setzen die berechneten Werte auf der viewBox.

// Wir speichern die ursprünglichen Werte aus der viewBox
var viewBox = {
x: 0,
y: 0,
Breite: 500,
Höhe: 500
};

// Die berechneten Entfernungen vom Zeiger werden hier gespeichert
var newViewBox = {
x: 0,
y: 0
};

// Funktion, die aufgerufen wird, die von der Ereignis-Listener, wenn user anfangen sich zu bewegen/ziehen
Funktion onPointerMove (event) {
// Nur ausführen dieser Funktion, wenn der Zeiger nach unten
if (!isPointerDown) {
return;
}
// Verhindern, dass Benutzer eine Auswahl auf der Seite
event.preventDefault();

// Den Zeiger positionieren
var pointerPosition = getPointFromEvent(event);

// Berechnen wir den Abstand zwischen dem Zeiger Herkunft und der aktuellen position
// Die viewBox in x – & y-Werte müssen berechnet werden aus der ursprünglichen Werte und die Entfernungen
newViewBox.x = viewBox.x – (pointerPosition.x – pointerOrigin.x);
newViewBox.y = viewBox.y – (pointerPosition.y – pointerOrigin.y);

// Wir erstellen einen string mit dem neuen viewBox-Werte
// X & Y-Werte sind gleich der aktuellen viewBox minus der berechneten Entfernungen
var viewBoxString = `${newViewBox.x} ${newViewBox.y} ${viewBox.Breite} ${viewBox.Höhe}`;
// Wir übernehmen die neuen viewBox-Werte auf den SVG
svg.setAttribute(‘viewBox’, viewBoxString);

Dokument.querySelector(‘.viewbox’).innerHTML = viewBoxString;
}

Wenn Sie sich nicht wohl fühlen mit dem Konzept der viewBox, würde ich dir empfehlen, Lesen Sie zuerst diese große Artikel von Sara Soueidan.

3. Speichern Aktualisiert viewBox

Nun, dass die viewBox wurde aktualisiert, wir müssen sparen, Ihre neuen Werte, wenn der Benutzer beendet das ziehen des SVG.

Dieser Schritt ist wichtig, denn sonst hätten wir berechnen immer die Zeiger-offsets von der ursprünglichen viewBox-Werte und der Benutzer ziehen Sie den SVG vom Ausgangspunkt, zu jeder Zeit.

Funktion onPointerUp() {
// Der Zeiger nicht mehr als nach unten
isPointerDown = false;

// Wir speichern das viewBox-Koordinaten basierend auf dem letzten Zeiger-offsets
viewBox.x = newViewBox.x;
viewBox.y = newViewBox.y;
}

4. Bearbeitung Dynamischer Viewport

Wenn wir eine benutzerdefinierte Breite auf unsere SVG, bemerken Sie möglicherweise während des Ziehens auf der demo unten, der Vogel bewegt sich entweder schneller oder langsamer als der pointer.

Finden Sie den Stift Dynamische viewport – SVG-Panning-von Louis Hoebregts (@Mamboleoo) auf CodePen.

Auf dem original-demo, die SVG-Breite ist genau passend zu seinem viewBox-Breite. Die tatsächliche Größe von Ihrer SVG kann auch viewport genannt. In einer perfekten situation, wenn der Benutzer bewegt den Zeiger von 1px, wir wollen das viewBox-übersetzen von 1px.

Aber, die meisten der Zeit, die SVG hat eine ansprechende Größe und die viewBox wird höchstwahrscheinlich nicht mit der SVG-Viewports. Wenn der SVG seine Breite ist doppelt so groß als die viewBox, wenn sich der Benutzer bewegt den Zeiger von 1px das Bild im SVG-übersetzen von 2px.

Um dies zu beheben, müssen wir berechnen das Verhältnis zwischen der viewBox und des Viewports, und wenden Sie dieses Verhältnis bei der Berechnung der neuen viewBox. Dieses Verhältnis muss ebenfalls aktualisiert werden, wenn die SVG-Größe ändern kann.

// Berechne die ratio auf der Basis der viewBox Breite und die SVG-Breite
var ratio = viewBox.Breite / svg.getBoundingClientRect().Breite;
Fenster.addEventListener(‘resize’, function() {
ratio = viewBox.Breite / svg.getBoundingClientRect().Breite;
});

Sobald wir wissen, dass die ratio, die wir brauchen, multiplizieren Sie die Maus offsets durch das Verhältnis proportional zu erhöhen oder verringern Sie den Abstand.

Funktion onMouseMove (e) {
[…]
newViewBox.x = viewBox.x – ((pointerPosition.x – pointerOrigin.x) * ratio);
newViewBox.y = viewBox.y – ((pointerPosition.y – pointerOrigin.y) * ratio);
[…]
}

Hier ist, wie diese funktioniert mit einem kleineren viewport als die viewBox-Breite:

Finden Sie den Stift Kleineren viewport – SVG-Panning-von Louis Hoebregts (@Mamboleoo) auf CodePen.

Und eine weitere demo mit einem viewport größer als die viewBox-Breite:

Finden Sie den Stift Größeren viewport – SVG-Panning-von Louis Hoebregts (@Mamboleoo) auf CodePen.

[Bonus] den code Optimieren

Um unseren code ein wenig kürzer, es gibt zwei sehr nützliche Konzepte im SVG, die wir nutzen könnten.

SVG-Punkte

Das erste Konzept ist die Verwendung von SVG-Punkte anstelle von grundlegenden Javascript-Objekte zu speichern, die Zeiger, die Positionen. Nach dem erstellen eines neuen SVG-Point-variable ist, können wir einige Matrix-Transformation auf es zu konvertieren, die die position relativ zu dem Bildschirm auf eine position relativ zur aktuellen SVG-benutzereinheiten.

Überprüfen Sie den code unten, um zu sehen, wie die Funktionen getPointFromEvent() und onPointerDown() geändert haben.

// Erstellen Sie ein SVG-Punkt, enthält x – & y-Werte
var point = svg.createSVGPoint();

Funktion getPointFromEvent (event) {
if (event.targetTouches) {
Punkt.x = event.targetTouches[0].clientX;
Punkt.y = event.targetTouches[0].clientY;
} else {
Punkt.x = event.clientX;
Punkt.y = event.clientY;
}

// Holen wir uns die aktuelle Transformationsmatrix von der SVG und wir inverser es
var invertedSVGMatrix = svg.getScreenCTM().inverse();

Rückkehr Punkt.matrixTransform(invertedSVGMatrix);
}

var pointerOrigin;
Funktion onPointerDown(event) {
isPointerDown = true; // Wir setzen den Mauszeiger als nach unten

// Holen wir uns die position des Mauszeigers beim klicken/touchdown, so können wir den Wert abrufen, sobald der Benutzer beginnt, ziehen
pointerOrigin = getPointFromEvent(event);
}

Durch die Verwendung von SVG-Punkte, die Sie gar nicht haben, um Transformationen angewendet auf Ihre SVG! Vergleichen Sie die folgenden zwei Beispiele, in denen die erste unterbrochen ist, wenn eine rotation angewandt auf die SVG-und im zweiten Beispiel verwendet SVG-Punkte.

Finden Sie die Stift-Demo + transformation – SVG-Panning-von Louis Hoebregts (@Mamboleoo) auf CodePen.

Finden Sie den Stift, Demo-Bonus + transform – SVG-Panning-von Louis Hoebregts (@Mamboleoo) auf CodePen.

SVG Animiert Rect

Der zweite unbekannte Konzept im SVG, die wir verwenden können, um zu verkürzen, die unseren code, ist die Verwendung von Animierten Rect.

Da die viewBox ist eigentlich als eine SVG-Rechteck (x, y, Breite, Höhe), können wir eine variable erstellen, die aus seiner Basis-Wert, wird automatisch eine Aktualisierung der viewBox, wenn wir aktualisieren diese variable.

Werden sehen wie einfach es ist jetzt ein update der viewBox des SVG!

// Wir speichern die ursprünglichen Werte aus der viewBox
var viewBox = svg.viewBox.baseVal;

Funktion onPointerMove (event) {
if (!isPointerDown) {
return;
}
event.preventDefault();

// Den Zeiger positionieren sich als SVG-Punkt
var pointerPosition = getPointFromEvent(event);

// Update das viewBox-variable mit dem Abstand vom Ursprung und aktuelle position
// Wir brauchen nicht zu kümmern, ein Verhältnis, weil das gehandhabt wird in der getPointFromEvent Funktion
viewBox.x -= (pointerPosition.x – pointerOrigin.x);
viewBox.y -= (pointerPosition.y – pointerOrigin.y);
}

Und hier ist die Letzte demo. Sehen Sie, wie viel kürzer ist der code nun? 😀

Finden Sie den Stift, Demo-Bonus – SVG-Panning-von Louis Hoebregts (@Mamboleoo) auf CodePen.

Fazit

Diese Lösung ist definitiv nicht der einzige Weg zu gehen, um solche Verhalten. Wenn Sie bereits eine Bibliothek an, Ihren Umgang mit SVGs, kann es schon eine eingebaute Funktion behandeln.

Ich hoffe dieser Artikel kann Ihnen helfen, zu verstehen, ein bisschen mehr, wie mächtig SVG kann! Fühlen Sie sich frei, um einen Beitrag zu den code durch Kommentare mit euren Ideen oder alternativen zu dieser Lösung.

Credits

  • Vogel entworfen durch Freepik
  • Ein großes Dankeschön an Blake für seine wertvolle Hilfe und all die netten Leute vom AAW Slack für Ihr feedback.