Recreating the Google Logo Animation with SVG and GreenSock

Avatar of Petr Tichy
Petr Tichy on

DigitalOcean bietet Cloud-Produkte für jede Phase Ihrer Reise. Starten Sie mit 200 $ kostenlosem Guthaben!

Der folgende Beitrag ist ein Gastbeitrag von Petr Tichy. Petr schreibt viel über Animation, Interaktion und SVG, daher freue ich mich, ihn hier zu haben, um einige dieser Fachkenntnisse mit einer so unterhaltsamen Demo zu teilen. Es ist eine Animation, die viele von Ihnen wahrscheinlich schon einmal gesehen haben, die aber magisch erscheint, vielleicht außerhalb dessen, was wir im Web tun können. Als ob sie von Videokünstlern / Videobearbeitungssoftware erstellt worden wäre. Aber nein, SVG kann das.

Vor einiger Zeit enthüllte Google sein aktualisiertes Branding und stellte die neue Identität auf einer Seite mit kreativen Animationen vor.

Ich habe versucht, einige dieser Animationen mit SVG und GreenSock nachzubilden. In diesem Artikel führe ich Sie Schritt für Schritt durch meinen Prozess. Hoffentlich können Sie dabei etwas lernen.

Hier ist die endgültige Animation

Siehe den Pen Google SVG Logo – GreenSock Animation von Petr TIchy (@ihatetomatoes) auf CodePen.

SVG in Illustrator einrichten

Der erste Schritt war die Erstellung einer SVG mit allen notwendigen Teilen, die animiert werden sollten. Ich habe eine .png-Aufnahme in Illustrator nachgezeichnet und eine einfache Umrisslinie des Kreises erstellt.

Um mir bei der korrekten Ausrichtung zu helfen, habe ich diesen Kreis in 4 gleiche Teile unterteilt. Dann habe ich 4 Kreise übereinander und 4 Punkte erstellt und versucht, so präzise wie möglich zu sein.

Ich wusste, dass ich GreenSock für die Animation verwenden würde, und ich wusste, dass die Kreise mit dem DrawSVGPlugin einfach zu animieren sein würden.

Um die Lücke zwischen der geraden Linie des „G“ und dem oberen Teil des Kreises zu erzeugen, habe ich ein unsichtbares weißes Element #gMask erstellt (#1 und #2 auf der unten stehenden Abbildung). Ziemlich hässlich, um ehrlich zu sein, aber es hat seinen Zweck erfüllt, die endgültige „G“-Form zu erzeugen.

Die Animation der geraden Linie wird aus 3 Teilen erstellt (#3 und #4 auf der unten stehenden Abbildung).

  • A – gerade Linie mit abgerundeter Kante – verwendet am Anfang der Linienanimation
  • B – clipPath-Maske – Beschnittbereich
  • C – gerade Linie – angezeigt am Ende der Animation

Noch in Illustrator habe ich alle Ebenen zu logischen Namen gruppiert und benannt. Das sparte mir später im Code-Editor Zeit. Das Gruppieren und Umbenennen von Elementen einer SVG kann in HTML recht langsam sein. Es ist viel einfacher, dies direkt in Illustrator zu tun.

Dann habe ich die SVG exportiert und sie durch Peter Collingridges SVG Online Editor laufen lassen, um einige Kilobytes einzusparen.

Die gesamte Animationssequenz kann in 3 Teile unterteilt werden

  1. Wellenanimation der Punkte
  2. Punkte in den Buchstaben „G“
  3. Von „G“ zurück zu den Punkten

Lassen Sie uns die einzelnen Teile detaillierter aufschlüsseln.

1. Wellenanimation der Punkte

Dies ist der erste Teil der Animation und er war am einfachsten zu erstellen.

Siehe den Pen Google SVG Logo – GreenSock Animation von Petr TIchy (@ihatetomatoes) auf CodePen.

Wir animieren einfach die Punkte auf und ab, indem wir die GreenSock .to() Methode verwenden.

Jeder Punkt hat seine eigene Timeline, dotWaveTl, die ihn nach y: -7, y: 7 und dann zurück nach y: 0 bewegt.

Alle vier Timelines werden dann mit einer leichten Verzögerung in eine Haupt-Timeline, dotsWaveTl, eingefügt.

Dies erzeugt den Welleneffekt aller vier Punkte.

function getDotsWaveTl(){
  var dotsWaveTl = new TimelineMax();

  $dots.each(function(index, element){

    var dotWaveTl = new TimelineMax(),
        delay = 0.15;

    dotWaveTl
      .to(element, 0.4, {y: -7, ease:Power1.easeOut})
      .to(element, 0.8, {y: 7, ease:Power1.easeInOut})
      .to(element, 0.4, {y: 0, ease:Power1.easeIn})
      .to(element, 0.4, {y: -7, ease:Power1.easeOut})
      .to(element, 0.8, {y: 7, ease:Power1.easeInOut})
      .to(element, 0.4, {y: 0, ease:Power1.easeIn});

    dotsWaveTl.add(dotWaveTl, delay*index);

  });

  return dotsWaveTl;
}

In dieser Funktion getDotsWaveTl durchlaufen wir alle Punkte, erstellen eine Timeline für jeden von ihnen und fügen diese Timelines dann in eine dotsWaveTl ein, die von dieser Funktion zurückgegeben wird.

Die einzelnen Tweens haben unterschiedliche Easing-Effekte, um diese Welle natürlicher wirken zu lassen.

Dann fügen wir diese Timeline einfach zur Master-Timeline tl hinzu.

/* Main timeline */
tl.add(getDotsWaveTl());

Wir werden die anderen Teile der Animationssequenz zu derselben Master-Timeline hinzufügen.

Wenn Sie mehr darüber erfahren möchten, wie GreenSock Timelines funktionieren, lesen Sie mein GreenSock TimelineLite Tutorial.

2. Punkte in den Buchstaben „G“

Dies war mit Abstand der schwierigste Teil der Animation.

Siehe den Pen Google SVG Logo – GreenSock Animation von Petr TIchy (@ihatetomatoes) auf CodePen.

Was machte es so schwer? Einiges. Ich musste

  • einen Pfad für jeden der Punkte ermitteln
  • ein präzises Timing für jeden der Punkte ermitteln
  • das Timing und die Animation für die gerade blaue Linie ermitteln
  • die Animationen der Punkte und der Linie synchronisieren

Wenn wir uns den Code ansehen, werden Sie sehen, dass dieser Teil der Animation aus zwei Timelines erstellt wird.

/* Dots rotation */
function getDotsRotateTl(){
  var dotsRotateTl = new TimelineMax();

  dotsRotateTl
    .to($dotRed, 0.9, {bezier:{curviness: 1.5, values: pathRed, ease:Power2.easeInOut}}, 0)
    .to($dotYellow, 1.2, {bezier:{curviness: 1, values: pathYellow, ease:Power2.easeInOut}}, 0)
    .to($dotGreen, 1.5, {bezier:{curviness: 1, values: pathGreen, ease:Power2.easeInOut}}, 0);

  return dotsRotateTl;
}

dotsRotateTl ist eine Timeline, in der ich rote, gelbe und grüne Punkte entlang eines Bézier-Pfades animiere. Ich kannte den Startpunkt und den Zielpunkt, und ich musste nur die Zwischenpunkte ermitteln.

pathRed ist ein Array von Punkten, die den Pfad für die Animation des roten Punktes definieren.

Die gleiche Technik wird für die gelben und grünen Punkte verwendet. Ich habe für jeden 4 Punkte definiert und die richtige Dauer ermittelt (1,2 s für den gelben und 1,5 s für den grünen Punkt).

Die zweite Timeline ist etwas komplexer.

/* Draw G */
function getDrawGTl(){
  var drawGTl = new TimelineMax();

  drawGTl
    .to($dotBlue, 0.6, {x: 47, ease:Power2.easeIn})
    .set($gLineAnim, {autoAlpha: 1, immediateRender: false})
    .set($dotBlue, {autoAlpha: 0, immediateRender: false}, '+=0.1')
    .from($gLineAnim, 0.8, {x: -120, ease:Power2.easeOut}, '-=0.2')

    /* draw red part */
    .add('startDrawingG', 1)
    .set($gRed, {autoAlpha: 1, immediateRender: false}, 'startDrawingG')
    .fromTo($gRed, 0.5, {drawSVG:"71% 88%"}, {drawSVG:"0% 26%", ease:Power1.easeOut}, '-=0.2')
    .set($dotRed, {autoAlpha: 0, immediateRender: false}, 'startDrawingG')

    /* draw yellow part */
    .set($gYellow, {autoAlpha: 1, immediateRender: false}, 'startDrawingG+=0.1')
    .fromTo($gYellow, 0.6, {drawSVG:"71% 88%"}, {drawSVG:"17% 36%", ease:Power2.easeOut}, '-=0.45')
    .set($dotYellow, {autoAlpha: 0, immediateRender: false}, 'startDrawingG+=0.1')

    /* draw green part */
    .set($gGreen, {autoAlpha: 1, immediateRender: false}, 'startDrawingG+=0.1')
    .fromTo($gGreen, 0.55, {drawSVG:"71% 88%"}, {drawSVG:"36% 61%", ease:Power2.easeOut}, '-=0.6')
    .set($dotGreen, {autoAlpha: 0, immediateRender: false}, 'startDrawingG+=0.4')

    /* draw blue part */
    .set($gLineAnim, {autoAlpha: 0, immediateRender: false}, 'startDrawingG+=0.3')
    .set($gLine, {autoAlpha: 1, immediateRender: false}, 'startDrawingG+=0.3')
    .set($gBlue, {autoAlpha: 1, immediateRender: false}, 'startDrawingG+=0.3')
    .fromTo($gBlue, 0.55, {drawSVG:"71% 88%"}, {drawSVG:"61% 78%", ease:Power2.easeOut}, '-=0.55')

    /* draw ending red part */
    .set($gRedb, {autoAlpha: 1, immediateRender: false}, 'startDrawingG+=0.25')
    .fromTo($gRedb, 0.7, {rotation: '-10', drawSVG:"100% 100%"}, {rotation: '0',drawSVG:"80% 100%", ease:Power2.easeOut}, '-=0.22');

  return drawGTl;
}

Die drawGTl Timeline steuert die Bewegung des blauen Punktes. Wenn er sich 47 Pixel nach rechts bewegt, verstecken wir ihn und zeigen die Linie mit abgerundeter rechter Kante (A) an, wie im zweiten Bild der SVG-Aufschlüsselung gezeigt.

Eine Sekunde nach dem Abspielen der drawGTl Timeline füge ich das Label startDrawingG ein. Dies ermöglicht es mir, andere Tweens zum richtigen Zeitpunkt hinzuzufügen und sie präzise durch Anpassung ihres Offsets zu steuern, z. B. startDrawingG+=0.3.

Sobald der rote Punkt den Schnittpunkt erreicht, verstecken wir ihn und zeigen den roten Kreis an, der dann mit dem GreenSock DrawSVGPlugin animiert wird.

.fromTo($gRed, 0.5, {drawSVG:"71% 88%"}, {drawSVG:"0% 26%", ease:Power1.easeOut}, '-=0.2')

Zu diesem Zeitpunkt und während der gesamten Entwicklung dieser Demo habe ich den jQuery UI Slider stark genutzt, um die richtigen Werte und Timings präzise zu ermitteln.

Sobald das rote Segment lange genug gezeichnet ist, machen wir dasselbe mit allen folgenden Segmenten.

Der Startpunkt ist für alle 71% 88% Segmente gleich, aber der Endpunkt ist für jedes von ihnen unterschiedlich.

Um das Zeichnen des gesamten Buchstabens „G“ mit dem DrawSVGPlugin abzuschließen, musste ich den roten Kreis duplizieren und den neuen $gRedb zum richtigen Zeitpunkt animieren.

Diese Änderung habe ich direkt im HTML vorgenommen; kein Zurückgehen nach Illustrator.

.fromTo($gRedb, 0.7, {rotation: '-10', drawSVG:"100% 100%"}, {rotation: '0', drawSVG:"80% 100%", ease:Power2.easeOut}, '-=0.22');

Eine Kombination aus Rotation, drawSVG-Werten, Timing und dem richtigen Offset ermöglichte es mir, die nahtlose Animation des roten Segments zu erstellen.

3. Von „G“ zurück zu den Punkten

Die Animation zurück zu den Punkten war viel einfacher zu erstellen. Ich habe die gleichen Techniken wie in der vorherigen Timeline verwendet, nur in umgekehrter Reihenfolge.

Siehe den Pen Google SVG Logo – GreenSock Animation von Petr TIchy (@ihatetomatoes) auf CodePen.

Ich habe zuerst das DrawSVGPlugin verwendet, um die farbigen Segmente kürzer zu machen, und dann begonnen, sie zu drehen.

Wenn das farbige Segment klein genug ist, verstecke ich es, zeige den entsprechenden Punkt und animiere ihn zur Ausgangsposition.

Hier ist eine Illustration, was auf der Timeline passiert

Und hier ist die gesamte Funktion, die diese Timeline zurückgibt

/* Back to dots */
function getBackToDotsTl(){
  var backToDotsTl = new TimelineMax();

  backToDotsTl
    /* blue straight line out */
    .to($gLineMask, 0.3, {attr: {x: 365}, transformOrigin: 'right center', ease:Power0.easeNone})
    .set([$gLineMask, $gLine], {autoAlpha: 0})

    /* start moving colored segments (circles) */
    .add('rotateG')
    .to($gBlue, 0.3, {drawSVG:"56% 78%", ease:Power0.easeNone}, 'rotateG-=0.3')
    .to($gGreen, 0.3, {drawSVG:"31% 56%", ease:Power0.easeNone}, 'rotateG-=0.3')
    .to($gYellow, 0.3, {drawSVG:"12% 31%", ease:Power0.easeNone}, 'rotateG-=0.3')
    .to($gRed, 0.3, {drawSVG:"0% 21%", ease:Power0.easeNone}, 'rotateG-=0.3')

    /* start rotating colored segments (circles) */
    .add('rotateCircles')
    .to([$gBlue, $gRed, $gGreen], 0.4, {rotation:"+=50", transformOrigin: 'center center', ease:Power0.easeNone}, 'rotateCircles')

    .to($gGreen, 0.4, {drawSVG:"10% 20%", ease:Power0.easeNone}, 'rotateCircles')
    .to($gYellow, 0.4, {rotation:"+=40", transformOrigin: 'center center', drawSVG:"0% 10%", ease:Power0.easeNone}, 'rotateCircles')
    .to($gBlue, 0.4, {drawSVG:"50% 60%", ease:Power0.easeNone}, 'rotateCircles')
    .to($gRed, 0.1, {drawSVG:"0% 0%", ease:Power0.easeNone}, 'rotateCircles')
    .to($gRedb, 0.3, {rotation:"+=50", drawSVG:"80% 90%", ease:Power2.easeInOut}, 'rotateCircles')

    /* show red dot */
    .set($dotRed, {autoAlpha: 1, x: 60, y: -37}, 'rotateCircles+=0.1')
    .set($gRedb, {autoAlpha: 0}, 'rotateCircles+=0.1')
    .to($dotRed, 0.9, {bezier:{curviness: 1.5, values: pathRedBack, ease:Power2.easeOut}}, 'rotateCircles+=0.1')

    /* show blue dot */
    .set($dotBlue, {autoAlpha: 1, x: 51, y: 53}, 'rotateCircles+=0.3')
    .set($gBlue, {autoAlpha: 0}, 'rotateCircles+=0.3')
    .to($dotBlue, 0.6, {bezier:{curviness: 1.5, values: pathBlueBack, ease:Power2.easeOut}}, 'rotateCircles+=0.3')

    /* show yellow dot */
    .set($dotYellow, {autoAlpha: 1, x: -5, y: -44}, 'rotateCircles+=0.4')
    .set($gYellow, {autoAlpha: 0}, 'rotateCircles+=0.4')
    .to($dotYellow, 0.7, {bezier:{curviness: 1.5, values: pathYellowBack, ease:Power2.easeOut}}, 'rotateCircles+=0.4')

    /* show green dot */
    .set($dotGreen, {autoAlpha: 1, x: -108, y: -56}, 'rotateCircles+=0.4')
    .set($gGreen, {autoAlpha: 0}, 'rotateCircles+=0.4')
    .to($dotGreen, 0.6, {bezier:{curviness: 1.5, values: pathGreenBack, ease:Power2.easeOut}}, 'rotateCircles+=0.4')

    .to($gMask, 0.3, {rotation:"+=60", transformOrigin: '-9 58', ease:Power2.easeInOut}, 'rotateCircles');

  return backToDotsTl;
}

Ich habe die Labels rotateG und rotateCircles verwendet, um die meisten Tweens auf dieser Timeline genau dort zu positionieren, wo ich sie haben wollte.

Dann habe ich diese Funktion in die Haupt-Timeline aufgenommen und die genaue Einfügezeit angepasst.

/* Main timeline */
tl.add(getDotsWaveTl())
  .add(getDotsRotateTl(), '-=0.35')
  .add(getDrawGTl(), '-=1.6')
  .add(getBackToDotsTl(), '+=2');

tl.timeScale(1.8);

getBackToDotsTl wird mit einer Verzögerung von 2 Sekunden eingefügt, ('+=2'), wodurch das „G“ für 2 Sekunden vollständig fertig bleibt, bevor es zurück zu den Punkten animiert wird.

Ich habe auch die Endgeschwindigkeit der Animation angepasst, indem ich die timeScale auf 1.8 anstelle des Standardwerts 1 gesetzt habe. Sie können den Wert gerne ändern, um die Animation mit einer anderen Geschwindigkeit zu sehen.

Die letzte Funktion, die erwähnt werden sollte, ist init().

/* Init */
function init(){
  TweenLite.set([$gLine,$circles], {autoAlpha: 0});
  TweenLite.set($gBlue, {drawSVG:"61% 78%"}); /* start at 71% 78% */
  TweenLite.set($gGreen, {drawSVG:"36% 61%"});
  TweenLite.set($gYellow, {drawSVG:"17% 36%"});
  TweenLite.set($gRed, {drawSVG:"0% 26%"});
  TweenLite.set($gRedb, {drawSVG:"78% 100%", transformOrigin: 'center center'});
  TweenLite.set($gLineAnim, {autoAlpha: 0});
}
init();

Dies ist eine Funktion, in der ich alles einrichte, z. B. einige Elemente ausblenden, Segmente auf die richtige Länge bringen usw.

Ich verwende diese Funktion bei komplexeren GSAP-Animationen wie diesem SVG GreenSock Lab, um den richtigen Startpunkt zu erhalten, den ich benötige, da ich in den meisten Fällen das endgültige Design oder den Frame, der alle Assets enthält, aus Illustrator exportiere.

Mit anderen Worten, diese Funktion bereitet die richtige Leinwand für den Anfang vor.

Warum habe ich GreenSock verwendet?

Es gibt bereits einige Artikel über GreenSock auf CSS-Tricks, daher gehe ich davon aus, dass Sie seine Stärken bereits kennen. Aber hier sind ein paar Gründe, warum ich diese Animationsbibliothek für diese Aufgabe ausgewählt habe:

  • GSAP gibt Ihnen präzise Kontrolle über Timing und Dauer von einzelnen Tweens und Timelines.
  • Die GSAP API bietet unglaublich flexible Verschachtelung von Timelines.
  • GSAP behebt viele browserübergreifende Inkonsistenzen bei der Arbeit mit SVGs.
  • Der jQuery UI Slider lässt Sie durch GSAP-Timelines schrubben und beschleunigt die Entwicklung.
  • GSAP ermöglicht es Ihnen, sich auf den kreativen Teil Ihrer interaktiven Projekte zu konzentrieren.
  • Die Verwendung von Labels ist großartig für komplexere Timelines.

Fazit

Ich weiß, dass einige der Code-Snippets und Timelines aus meiner Animation überwältigend aussehen könnten. Zögern Sie nicht, Fragen in den Kommentaren unten zu stellen oder mich auf Twitter zu kontaktieren @ihatetomatoes.