SVG im wirklichen Leben. Yandex-Bericht

Hallo, mein Name ist Artyom, ich bin der Leiter einer der Interface-Entwicklungsgruppen in Yandex. Vor einer Woche habe ich auf Ya. Subbotnik erzählt, wie wir mit SVG einen internen Kalender erstellt haben. Dies ist eine Abschrift meines Berichts, einige Geschichten aus der Implementierung des Kalender-Widgets: Skalierung, Musterfüllung, Masken, Symbole und Formatfunktionen.



- In Yandex arbeiten viele Menschen in verschiedenen Städten und Zeitzonen. Sie müssen verstehen, wann Ihre Kollegen beschäftigt sind und wann Sie sie treffen und mit ihnen sprechen können. Wir haben uns entschlossen, einen Kalender zu entwerfen, der Ihnen dabei hilft, dies herauszufinden.

Wir haben natürlich mit einem Layout begonnen. Er sah so aus:



Es zeigt gerade und ungerade Ereignisse mit unterschiedlichen Füllungen. Ereignisse, die andere Ereignisse überlappen, dh sich auf der zweiten Ebene befinden - eine weitere Füllung. Ereignisse, die den ganzen Tag dauern, übermalen den ganzen Tag. Die aktuelle Uhrzeit wird unten angezeigt. Das war das Ziel.



Wir begannen zu entscheiden, was wir tun wollen. Verschiedene Prototypen hergestellt. Wir haben mit Canvas angefangen, aber es gab viel Code, der manuell skaliert wurde, um zu schreiben. Wir hatten die Idee, dass der Kalender so viel Platz wie nötig einnimmt, in verschiedenen Layouts unterschiedliche Formen und Größen hat. Und für Leinwand war es kompliziert.

Es gab einen coolen Prototyp, als wir dieses ganze Bild mit linearen Verläufen erzeugten, aber er bewegte sich beim Skalieren und beim Umschalten auf die Netzhaut heraus. Deshalb sind wir am Ende zu SVG gekommen. Warum? Erstens gibt es ein Koordinatensystem, das völlig unabhängig vom Dokument ist, sodass Sie alles im Inneren vollständig positionieren können, und dies wird unabhängig von nichts kaputt gehen. Es gibt auch normale Arbeit mit Skalierung. Selbst wenn Sie in den Browser zoomen, wenn Sie die Netzhaut öffnen oder den Kalender irgendwie dehnen, wird die Größe wie ein Bild geändert und sieht auf jeden Fall normal aus. Wir hatten eine Zellenfüllung im Layout und es ist sehr gut, dass SVG eine Musterfüllung hat.



Um einen Kalender zu zeichnen, benötigen Sie einige Daten. Um das Datum auf dem Layout zu zeichnen, müssen Sie wissen, an welchem ​​Datum es beginnt - normalerweise am aktuellen -, um zu wissen, wie viele Tage horizontal sein sollten, wie viele Stunden vertikal angezeigt werden sollten und zu welcher Stunde der Tag im Kalender beginnt. Wir müssen irgendwie Ereignisse bekommen.

Da wir viele Büros in verschiedenen Zeitzonen haben, haben wir beschlossen, dass Ereignisse immer in UTC eintreffen, und wir werden sie den Benutzern bereits auf dem Client anzeigen, da der Kalender für unsere Zeitzone und für die Zeitzone der Person angezeigt werden muss. Wessen Kalender sehen Sie sich an - um zu verstehen, dass es jetzt Nacht ist und es besser ist, keinen Termin zu vereinbaren. Was rot hervorgehoben ist, wird später verwendet.



Beginnen wir mit den Grundlagen. SVG ist eine riesige Koordinatenebene, auf der Vektorgrafiken beliebig platziert werden können. Gleichzeitig wird der Teil des Bereichs, den wir sehen, von der viewBox bestimmt, und was sich hinter seinen Grenzen befindet, ist ein solcher Überlauf, der auf Steroiden verborgen ist. Was auch immer es ist, es wird nicht sichtbar sein. Wir haben beschlossen, dass wir zur Vereinfachung der Berechnungen ein Pixel im Kalender einer Minute entsprechen lassen. Daher nimmt eine Stunde genau 60 Pixel ein. Um es noch einfacher zu machen, haben wir beschlossen, dass der Tag in der Breite auch 60 Pixel betragen würde - so dass alles quadratisch war, wie in der Armee. Und sie fingen an zu setzen.

Viewbox wird durch vier Parameter eingestellt. Die ersten beiden sind der obere linke Punkt im Koordinatensystem, von dem aus die viewBox betrachtet wird. Für uns ist sie 0.0. Die Breite beträgt 60 * für die Anzahl der Tage und die Höhe 60 * für die Anzahl der Stunden.

Es ist gültig, andere SVG-Dokumente in die SVG einzufügen, die ein eigenes Koordinatensystem enthalten. Damit die Ereignisse am Tag nur entlang der vertikalen Achse positioniert werden können, haben wir beschlossen, dass wir für jeden Tag eine separate SVG haben und sie nur horizontal um 60 * an die Position des Tages im Kalender verschieben. Dann können alle Ereignisse einfach vertikal in Y eingestellt werden, was sehr praktisch ist. Und in jede SVG, die ein Tag ist, setzen wir ein Rechteck, das die Füllung des Tages anzeigt.

Da keine Füllfarbe angegeben ist, erbt dieses Rechteck die Fülleigenschaft von SVG. In diesem Fall funktioniert dieser Tag und zwei Tage die Woche frei, sodass sie mit Licht überflutet sind. Dies wird nur durch die Klassen bestimmt.



Es ist ein Leerzeichen. Jetzt müssen Sie das Raster hinzufügen. Da wir die Größe des Kalenders ändern wollten und die Gitterlinien immer ein Pixel sein sollten, haben wir das Attribut vector-effect = non-scaling-Stroke verwendet. Dies führt dazu, dass unabhängig von der Größe oder dem Zoom immer ein Einzelpixel-Raster vorhanden ist. Es reicht aus, nur die richtige Anzahl horizontaler und vertikaler Linien hinzuzufügen, und es wird ein solches Raster geben.



Wir haben die Basis herausgefunden und gehen zu den ganztägigen Veranstaltungen über. Das ist so eine knifflige Sache. Sie haben festgestellt, dass Ereignisse in den Kalendern und ein Häkchen für den ganzen Tag angezeigt werden. Diese Ereignisse unterscheiden sich darin, dass sie den ganzen Tag andauern, unabhängig davon, in welcher Zeitzone Sie sich befinden. Wenn das Ereignis also irgendwo am Anfang der Zeitzonen in Alaska am frühen Morgen beginnt, dann wird es irgendwo in 48 Stunden am anderen Ende der Welt immer noch weitergehen. Es klingt kompliziert, ist aber am einfachsten zu implementieren: Vergleichen Sie einfach das Datum mit dem Datum des angezeigten Tages. Wenn es trifft, bedeutet es ein Ereignis an diesem Tag. Wenn zwei Ereignisse für den ganzen Tag auf den Tag fallen, wird das später begonnene angezeigt. Füllen Sie also Shows für den ganzen Tag.



Bei anderen Veranstaltungen ist es etwas schwieriger. Es gibt zum Beispiel ein Treffen. Es ist blau gefüllt, alles ist einfach. Wenn jedoch zwei Besprechungen hintereinander stattfinden, füllen wir sie gemäß unserem Layout mit unterschiedlichen Farben. Sie sind gerade und ungerade.

Wenn sich ein Meeting mit einem anderen überschneidet und höher liegt, müssen Sie es irgendwie anzeigen. Wenn es Schnittpunkte mit Besprechungen gibt, werden diese vollständig separat in Zellen gegossen. Und damit wir noch mehr Spaß haben, haben wir nicht nur Besprechungen, sondern auch Abwesenheiten, Konferenzen und vieles mehr. Ich wollte das alles nicht im Layout fest codieren, deshalb haben wir uns entschlossen herauszufinden, wie es mehr oder weniger browserübergreifend und bequem in CSS zu konfigurieren ist.



Jetzt wird es das schwierigste Beispiel aus dem gesamten Bericht geben, seien Sie geduldig und beobachten Sie, es wird drei Schritte geben, dann wird es einfacher.

Beginnen wir in der richtigen Reihenfolge. SVG verfügt über ein <defs> -Tag, mit dem Sie Elemente deklarieren können, die nicht angezeigt werden. Sie können sie jedoch als Referenz verwenden und auf sie verweisen. Als erstes deklarieren wir <defs> und erstellen ein Muster darin. <Muster> ist ein Tag, mit dem Sie ein Muster deklarieren können, mit dem Sie ein bestimmtes Element mit einem bestimmten Muster füllen können.

Wir müssen Zellen in diesem Muster herstellen. Wir haben 60 x 60 Pixel, die Zellen sollten 6 x 6 sein, also haben wir ein 12 x 12-Muster deklariert und einen <Pfad> darin gezeichnet, wie im Diagramm links. Es hat ein Attribut d, das genau angibt, wie sich die Linie bewegt. Es beginnt am Punkt 0,0, und dann zeigen die Koordinaten den Pfeilen, wie es gezeichnet wird. Wenn wir es mit Weiß füllen, erhalten wir das folgende Muster: Was nicht mit Weiß überflutet ist, ist mit Schwarz überflutet.



Fahren Sie mit dem nächsten Schritt fort und deklarieren Sie nun die Maske. <mask> ist ein solches Element in SVG, mit dem Sie anderen Elementen einen Alphakanal hinzufügen können. Was in der Maske in dem Element, auf das die Maske angewendet wird, schwarz gezeichnet ist, ist unsichtbar und transparent. Was weiß gestrichen ist, ist undurchsichtig. Was grau ist, ist durchscheinend. Wir haben ein Schwarz-Weiß-Muster, und wir werden ein Rechteck in die Maske einfügen und es mit diesem Muster füllen. Jetzt haben wir eine Maske.

Der nächste Schritt ist <Symbol>. Dies ist ein solches Tag in SVG, mit dem Sie wiederverwendbare Grafiken deklarieren können. Am häufigsten werden Symbole beispielsweise für Symbole verwendet. Und hier deklarieren wir ein Symbol, in das wir zwei Rechtecke setzen. Einer füllt nichts, sodass er die Fülleigenschaft von der übergeordneten SVG erbt, und der andere füllt sich mit currentColor und wendet eine Maske darauf an. Jetzt haben wir zwei Rechtecke: eines mit Löchern und gefüllt mit currentColor und das andere ohne Löcher und gefüllt mit Füllung. Und sie liegen übereinander. Wenn wir diese Farben gleich einstellen, erhalten wir eine feste Füllung. Und wenn anders - Zellen. Das alles ging. Jetzt können Sie einfach CSS verwenden und durch Klassen eine beliebige Füllung aus zwei Farben für alle Ereignisse festlegen.



Jetzt müssen Sie genau festlegen, welche Ereignisse an einem bestimmten Tag in den Kalender aufgenommen werden sollen. Wir haben eine Zeitzone von +3, in der wir alle sitzen, sie hat eine Skala von 9 bis 20 Stunden. Es gibt auch eine Person, die im bedingten Orenburg sitzt, er hat eine Zeitzone von +5, seine Skala ist gegenüber uns um zwei Stunden versetzt. Wir werden eine Projektion auf UTC machen und sehen, dass auf UTC dieses Intervall von oben nach unten unten angezeigt werden muss, damit der Benutzer beim Umschalten zwischen Zeitzonen sowohl die Ereignisse sehen kann, die in seinen Kalender fallen, als auch den Kalender der Person, die er betrachtet .

Denken Sie an diese versetzten Zahlen, da es am einfachsten ist, die in UTC eintreffenden Ereignisse in derselben UTC zu positionieren. Dazu nehmen wir das <g> -Tag, das eine Gruppe in SVG bezeichnet, und positionieren alle Ereignisse dort absolut nach UTC. Wir verschieben <g> um die Anzahl der Pixel, die wir zum Anzeigen der einen oder anderen Zeitzone benötigen.



Wenn wir diese Studie zusammenfassen, erhalten wir ein Symbol, auf das wir uns beziehen. Es gibt einen Ereignistyp, eine Ebene, eine Parität, -120 Minuten ab Tagesbeginn in UTC und eine Dauer von 30 Minuten. Durch Hinzufügen aller Ereignisse erhalten wir ein solches Bild.



Die aktuelle Zeit wird auch einfach gemacht, es wird eine Linie mit dem gleichen nicht skalierenden Stricheffekt sein, so dass es immer ein Pixel ist. So wird es angezeigt.

Die Zeit steht nicht still und der Pfeil muss sich bewegen. Der coolste Weg, den wir uns ausgedacht haben, ist die Animation. Wir haben beschlossen, eine Animation zu erstellen, die den Pfeil um die Anzahl der Minuten pro Tag verschiebt und dies an einem Tag tut. Und damit es sich nicht ständig langsam bewegt, nämlich einmal pro Minute tickt, haben wir step () verwendet. Und sobald wir es hinzufügten, begann sich die Zeit zu bewegen. Da die Animation nicht garantiert, dass sie sich ständig bewegt, bleibt sie entweder zurück oder etwas anderes. Unsere Ereignisse im Kalender werden jedoch von Zeit zu Zeit aktualisiert. Irgendwo alle zwei oder drei Minuten oder wenn der Benutzer den Tab verlassen und zurückgekehrt ist, wird der gesamte Kalender neu gezeichnet und die Zeit aktualisiert. Daher ist die Animation nur sichtbar, wenn Sie sitzen und genau beobachten, ob sie tickt oder nicht.



Es gibt ein Problem. Hier habe ich einen Kalender breiter gemacht, damit er eher dem in der Produktion ähnelt. Es wurde klar, dass die Zellen nicht mehr quadratisch sind. Dies liegt daran, dass die Proportionen nicht erhalten bleiben. Wenn wir das Seitenverhältnis physisch dehnen oder ändern, ändert es sich wie auf dem Bild. Um dies zu vermeiden, müssen Sie ein wenig JS schreiben. Es gibt das Seitenverhältnis viewBox, das in unserer ursprünglichen SVG enthalten war, und das tatsächliche Seitenverhältnis, das in unserem Layout verwendet wird. Wenn Sie das Verhältnis dieser Verhältnisse finden und es dann in die Transformation des Musters einfügen, werden die Zellen quadratisch. Und auch dieser Koeffizient, den wir hier erhalten haben, kann verwendet werden, wenn wir verstehen wollen, wo der Benutzer geklickt hat. Da wir im ursprünglichen SVG eine Minute haben, die einem Pixel entspricht, können wir anhand der Koordinaten des Klicks multipliziert mit diesem Koeffizienten verstehen, zu welcher Zeit der Benutzer gekommen ist.



Es bleibt noch HTML hinzuzufügen, damit Buchstaben und Zahlen oben sind. Holen Sie sich einen Kalender.



So sieht dieses Ding in der Produktion mit den Augen eines Benutzers aus, der in der Zeitzone +5 sitzt. Unten ist ein Kippschalter, den mein Kollege drückt, und der Kalender bewegt sich in Zeitzonen. Dann klickt er auf das Ereignis und sieht, dass am Samstag in der Zeitzone +5, das heißt, mein Bericht läuft.



Noch ein paar Beispiele. Hier ist der Kalender des Entwicklers, er hat Stand-Ups, mehrere regelmäßige Meetings und das wars. Hier ist der Kalender des Managers. Und hier ist der Designer.

Verwenden Sie CSS, verwenden Sie SVG. Vielen Dank!

Source: https://habr.com/ru/post/de461571/


All Articles