Het maken van een Panning Effect voor SVG –

0
37

Eerder deze maand op de Animatie op het Werk Slap, we hadden een discussie over het vinden van een manier om de gebruikers te laten pan in een SVG.

Ik heb deze demo hieronder om te laten zien hoe ik zou benadering deze vraag:

Zie de Pen Demo – SVG Panning door Louis Hoebregts (@Mamboleoo) op CodePen.

Hier zijn de vier stappen voor het maken van de demo-werk:

  1. Voor muis en druk op de gebeurtenissen van de gebruiker
  2. Het berekenen van de muis verschuivingen van de oorsprong
  3. Sla de nieuwe viewBox coördinaten
  4. Handvat dynamische kijkvenster

Laten we deze stappen één voor één grondig.

1. Muis & Touch Events

Om de muis of touch-positie, moeten we eerst add event listeners op onze SVG. We kunnen gebruik maken van de Aanwijzer Evenementen voor het verwerken van alle soort van wijzers (muis/touch/stylus/…), maar deze gebeurtenissen zijn nog niet door alle browsers ondersteund. We zullen er moeten aan toevoegen terugval zorg ervoor dat alle gebruikers in staat zal zijn om te slepen van de SVG.

// Wij selecteren de SVG op de pagina in
var svg – = – document.querySelector(‘svg’);

// Als de browser ondersteunt aanwijzer evenementen
if (window.PointerEvent) {
svg.addEventListener(‘pointerdown’, onPointerDown); // Pointer wordt ingedrukt
svg.addEventListener(‘pointerup’, onPointerUp); // het Loslaten van de aanwijzer
svg.addEventListener(‘pointerleave’, onPointerUp); // Pointer komt uit de SVG-gebied
svg.addEventListener(‘pointermove’, onPointerMove); // Pointer beweegt
} else {
// Voeg alle mouse events luisteraars fallback
svg.addEventListener(‘mousedown’, onPointerDown); // bij het Indrukken van de muis
svg.addEventListener(‘mouseup’, onPointerUp); // het Loslaten van de muis
svg.addEventListener(‘mouseleave’, onPointerUp); // Muis komt uit de SVG-gebied
svg.addEventListener(‘mousemove’, onPointerMove); // Muis beweegt

// Voeg alle touch events luisteraars fallback
svg.addEventListener(‘touchstart’, onPointerDown); // Vinger het scherm aan te raken
svg.addEventListener(‘touchend’, onPointerUp); // Vinger is niet langer het aanraken van het scherm
svg.addEventListener(‘touchmove’, onPointerMove); // Vinger beweegt
}

Omdat wij konden touch events en wijzer gebeurtenissen, moeten we een kleine functie keert terug naar de coördinaten van de eerste vinger van een aanwijzer.

// Deze functie geeft als resultaat een object met X En Y-waarden van de aanwijzer evenement
functie getPointFromEvent (event) {
var punt = {x:0, y:0};
// Als de gebeurtenis wordt geactiveerd door een touch event, krijgen we de positie van de eerste vinger
als (event.targetTouches) {
punt.x = gebeurtenis.targetTouches[0].clientX;
punt.y = gebeurtenis.targetTouches[0].clientY;
} else {
punt.x = gebeurtenis.clientX;
punt.y = gebeurtenis.clientY;
}

keerpunt;
}

Zodra de pagina is klaar en wacht op eventuele interacties van de gebruiker, kunnen we beginnen met de afhandeling van de gebeurtenissen mousedown/touchstart gebeurtenissen op te slaan in de oorspronkelijke coördinaten van de aanwijzer en het maken van een variabele om ons te laten weten als u de muisaanwijzer naar beneden of niet.

// Deze variabele wordt later gebruikt voor het verplaatsen van de gebeurtenissen om te controleren of de aanwijzer is of niet
var isPointerDown = false;

// Deze variabele bevat de oorspronkelijke coördinaten wanneer de gebruiker start het indrukken van de muis of het aanraken van het scherm
var pointerOrigin = {
x: 0,
y: 0
};

// Functie die wordt aangeroepen door de event listeners wanneer de gebruiker begint te drukken op/aan te raken
functie onPointerDown(event) {
isPointerDown = true; // We zetten de muisaanwijzer naar beneden als

// We krijgen van de positie van de aanwijzer op klik/touchdown, zodat we kunnen krijgen van de waarde zodra de gebruiker begint te slepen
var pointerPosition = getPointFromEvent(evenement);
pointerOrigin.x = pointerPosition.x;
pointerOrigin.y = pointerPosition.y;
}

2. Bereken Muis Offsets

Nu hebben we de coördinaten van de plaats waar de gebruiker de slag te slepen in de SVG, kunnen we berekenen de afstand tussen de huidige positie van de muisaanwijzer en de herkomst. Wij doen dit voor zowel de X-en Y-as en we passen de berekende waarden op de viewBox.

// We slaan de oorspronkelijke waarden van de viewBox
var viewBox = {
x: 0,
y: 0,
breedte: 500,
hoogte: 500
};

// De berekende afstanden van de aanwijzer worden hier opgeslagen
var newViewBox = {
x: 0,
y: 0
};

// Functie die wordt aangeroepen door de event listeners wanneer de gebruiker begint te verplaatsen/slepen
functie onPointerMove (event) {
// Alleen het uitvoeren van deze functie als u de muisaanwijzer naar beneden
if (!isPointerDown) {
return;
}
// Dit voorkomt dat de gebruiker een selectie op de pagina
evenement.preventDefault();

// Voor de positie van de aanwijzer
var pointerPosition = getPointFromEvent(evenement);

// We berekenen de afstand tussen de aanwijzer oorsprong en de huidige positie
// De viewBox x & y-waarden moeten worden berekend op basis van de oorspronkelijke waarden en de afstanden
newViewBox.x = viewBox.x – (pointerPosition.x – pointerOrigin.x);
newViewBox.y = viewBox.y – (pointerPosition.y – pointerOrigin.y);

// We maken een string met de nieuwe waarden viewBox
// De X En de Y-waarden gelijk zijn aan de huidige viewBox minus de berekende afstanden
var viewBoxString = `${newViewBox.x} ${newViewBox.y} ${viewBox.breedte} ${viewBox.hoogte}`;
// We passen de nieuwe viewBox waarden op de SVG
svg.setAttribute(‘viewBox’, viewBoxString);

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

Als je niet comfortabel voelt met het concept van viewBox, ik zou je aanraden eerst lees dit grote artikel door Sara Soueidan.

3. Bespaar Bijgewerkt viewBox

Nu dat de viewBox is bijgewerkt, die we nodig hebben om het opslaan van de nieuwe waarden wanneer de gebruiker stopt met het slepen van de SVG.

Deze stap is belangrijk, want anders zouden we altijd de berekening van de aanwijzer verschuivingen ten opzichte van het oorspronkelijke viewBox waarden en de gebruiker sleep de SVG van het beginpunt van elke tijd.

functie onPointerUp() {
// De aanwijzer wordt niet langer beschouwd als beneden
isPointerDown = false;

// We slaan de viewBox coördinaten gebaseerd op de laatste aanwijzer offsets
viewBox.x = newViewBox.x;
viewBox.y = newViewBox.y;
}

4. Handvat Dynamische Kijkvenster

Als we een aangepaste breedte in op onze SVG, ziet u tijdens het slepen op de demo hieronder dat de vogel in beweging is zowel sneller of langzamer dan de aanwijzer.

Zie de Pen Dynamische viewport – SVG Panning door Louis Hoebregts (@Mamboleoo) op CodePen.

Op de originele demo, de SVG de breedte is precies overeenkomt met de viewBox breedte. De werkelijke grootte van uw SVG-kan ook worden genoemd viewport. In een perfecte situatie, wanneer de gebruiker is het verplaatsen van de aanwijzer door 1px, we willen de viewBox te vertalen door 1px.

Maar, de meeste van de tijd, de SVG heeft een responsieve grootte en de viewBox zal waarschijnlijk niet overeen met de SVG-viewport. Als de SVG-de breedte is twee keer zo groot dan de viewBox, wanneer de gebruiker verplaatst de pointer door 1px, de afbeelding aan de binnenkant van de SVG vertalen door 2px.

Om dit op te lossen, moeten we voor het berekenen van de verhouding tussen de viewBox en de viewport en toepassen van deze ratio, terwijl de berekening van de nieuwe viewBox. Deze verhouding moet ook worden bijgewerkt wanneer het SVG-formaat kan wijzigen.

// Bereken de verhouding op basis van de viewBox breedte en de SVG-breedte
var-ratio = viewBox.breedte / svg.getBoundingClientRect().breedte;
venster.addEventListener(‘resize’, function() {
ratio = viewBox.breedte / svg.getBoundingClientRect().breedte;
});

Zodra we weten wat de verhoudingis, moeten we vermenigvuldigen met de muis verschuift door de verhouding proportioneel vergroten of verminderen van de compensatie.

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

Hier is hoe dit werkt met een kleinere viewport dan de viewBox breedte:

Zie de Pen Kleinere viewport – SVG Panning door Louis Hoebregts (@Mamboleoo) op CodePen.

En nog een demo met een viewport groter dan de viewBox breedte:

Zie de Pen Grotere viewport – SVG Panning door Louis Hoebregts (@Mamboleoo) op CodePen.

[Bonus]. het Optimaliseren van de code

Aan onze code een beetje korter, er zijn twee bruikbare concepten in SVG we kunnen gebruiken.

SVG Punten

Het eerste concept is het gebruik van SVG Punten in plaats van op basis van Javascript-objecten op te slaan van de aanwijzer posities. Na het aanmaken van een nieuwe SVG-variabele, kunnen we een aantal matrixtransformatie op het converteren van de relatieve positie van het scherm naar een positie ten opzichte van de huidige SVG-gebruiker-eenheden.

Check de onderstaande code om te zien hoe de functies getPointFromEvent() en onPointerDown() gewijzigd.

// Maak een SVG punt waarin x en y-waarden
var punt = svg.createSVGPoint();

functie getPointFromEvent (event) {
als (event.targetTouches) {
punt.x = gebeurtenis.targetTouches[0].clientX;
punt.y = gebeurtenis.targetTouches[0].clientY;
} else {
punt.x = gebeurtenis.clientX;
punt.y = gebeurtenis.clientY;
}

// We krijgen de huidige transformatie matrix van de SVG en we het inverse
var invertedSVGMatrix = svg.getScreenCTM().inverse();

terug punt.matrixTransform(invertedSVGMatrix);
}

var pointerOrigin;
functie onPointerDown(event) {
isPointerDown = true; // We zetten de muisaanwijzer naar beneden als

// We krijgen van de positie van de aanwijzer op klik/touchdown, zodat we kunnen krijgen van de waarde zodra de gebruiker begint te slepen
pointerOrigin = getPointFromEvent(evenement);
}

Door het gebruik van SVG Punten, je hoeft zelfs niet te behandelen transformaties toegepast op uw SVG! Vergelijk de volgende twee voorbeelden waar de eerste is gebroken wanneer een rotatie wordt toegepast op de SVG en de tweede voorbeeld SVG-Punten.

Zie de Pen Demo + transformatie – SVG Panning door Louis Hoebregts (@Mamboleoo) op CodePen.

Zie de Pen Demo Bonus + transformeren – SVG Panning door Louis Hoebregts (@Mamboleoo) op CodePen.

SVG Geanimeerde Rect

De tweede onbekende concept in SVG we kunnen gebruiken om het verkorten van onze code, is het gebruik van Geanimeerde Rect.

Omdat de viewBox is in feite beschouwd als een SVG-Rechthoek (x, y, width, height), kunnen we een variabele maken van de basis waarde die wordt automatisch bijwerken van de viewBox als we een update van deze variabele.

Zie hoe makkelijker het is nu voor het bijwerken van de viewBox van onze SVG!

// We slaan de oorspronkelijke waarden van de viewBox
var viewBox = svg.viewBox.baseVal;

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

// Voor de positie van de muisaanwijzer als een SVG-Punt
var pointerPosition = getPointFromEvent(evenement);

// Update de viewBox variabele met de afstand van de oorsprong en de huidige positie
// We hoeven niet te verzorgen van een verhouding, omdat deze is verwerkt in de getPointFromEvent functie
viewBox.x -= (pointerPosition.x – pointerOrigin.x);
viewBox.y -= (pointerPosition.y – pointerOrigin.y);
}

En hier is de laatste demo. Zie hoeveel korter de code is nu? 😀

Zie de Pen Demo Bonus – SVG Panning door Louis Hoebregts (@Mamboleoo) op CodePen.

Conclusie

Deze oplossing is zeker niet de enige manier om te gaan voor het afhandelen van dergelijke gedrag. Als u reeds gebruik van een bibliotheek om om te gaan met uw SVGs, het kan al een ingebouwde functie om te gaan.

Ik hoop dat dit artikel kan u helpen te begrijpen een beetje meer hoe krachtig SVG kan worden! Voel je vrij om bij te dragen aan de code van commentaar met uw ideeën of alternatieven voor deze oplossing.

Credits

  • Vogel ontworpen door Freepik
  • Een grote dank aan Blake voor zijn waardevolle hulp en alle leuke mensen van de AAW Slap voor hun feedback.