Lassen Sie uns einige Dinge betrachten, die ich über das Positionieren von Elementen innerhalb von SVG gelernt habe und die ich diese Woche bei der Erstellung eines (scheinbar) einfachen Balkendiagramms entdeckt habe.
In SVG hat man nicht viel Wahl, als Dinge zu positionieren. SVG ist ein deklaratives Grafikformat, und was sind Grafiken anderes als positionierte Zeichenanweisungen? Es gibt jedoch viele Tücken und potenziell frustrierende Situationen, also legen wir los.
Dies ist das Balkendiagramm, das wir bauen wollen

Wir könnten dies in unserem bevorzugten Grafikeditor erstellen und es als <img>-Tag (sogar als `.svg`) in unser Markup einfügen, aber wo bliebe da der Spaß? Ich wollte dieses SVG-Diagramm auch von Hand erstellen, weil ich wusste, dass ich mehr über die Syntax lernen würde, als wenn ich einfach eine Sketch- oder Illustrator-Datei exportieren würde.
Um die Dinge in Bewegung zu setzen, erstellen wir ein <svg>, das unsere Kindelemente aufnehmen wird
<svg width='100%' height='65px'>
</svg>
Nun erstellen wir die beiden Balken. Der erste wird im Hintergrund liegen und der zweite wird darüber liegen und die Daten unseres Diagramms darstellen.
<svg width='100%' height='65px'>
<g class='bars'>
<rect fill='#3d5599' width='100%' height='25'></rect>;
<rect fill='#cb4d3e' width='45%' height='25'></rect>
</g>
</svg>
(Ohne Angabe eines x- und y-Attributs für die <rect>s werden diese als 0 angenommen.)
In der untenstehenden Demo habe ich sie animiert, damit Sie sehen können, dass das zweite Rechteck über dem ersten platziert wird (dies wäre so, als würde man zwei Rechtecke in Sketch zeichnen, eines liegt über dem anderen).
Als Nächstes können wir die Linien hinzufügen, die als Markierungen dienen, um die Daten bei 0, 25, 50, 75 und 100 % leichter ablesen zu können. Alles, was wir tun müssen, ist eine neue Gruppe zu erstellen und für jede Markierung ein Rechteck hinzuzufügen, richtig? Sicher, aber Sie werden gleich ein kleines Problem sehen.
Innerhalb des SVG, und unter dem <g>-Tag, in dem wir die Daten unseres Diagramms gestylt haben, können wir Folgendes schreiben
<g class='markers'>
<rect fill='red' x='50%' y='0' width='2' height='35'></rect>
</g>
Das sollte so aussehen
Schick! Fügen wir all die anderen Markierungen hinzu und korrigieren dabei die Farben.
<g class='markers'>
<rect fill='#001f3f' x='0%' y='0' width='2' height='35'></rect>
<rect fill='#001f3f' x='25%' y='0' width='2' height='35'></rect>
<rect fill='#001f3f' x='50%' y='0' width='2' height='35'></rect>
<rect fill='#001f3f' x='75%' y='0' width='2' height='35'></rect>
<rect fill='#001f3f' x='100%' y='0' width='2' height='35'></rect>
</g>
Wir haben für jede Markierung ein <rect> hinzugefügt, eine Füllung zur Festlegung der Farbe und sie mit dem x-Attribut positioniert. Sehen wir uns an, wie das im Browser gerendert wird.
Wo zum Teufel ist die letzte verschwunden? Nun, wir haben ihr gesagt, sie soll bei 100 % positioniert werden, daher ist sie tatsächlich außerhalb des Bildschirms nach rechts positioniert. Wir müssen ihre Breite berücksichtigen und sie um 2 nach links verschieben. Es gibt eine Reihe von Möglichkeiten, dies zu beheben.
1) Wir könnten eine Inline-Transformation anwenden, um sie wieder nach vorne zu schieben.
<rect fill='#001f3f' x='100%' y='0' width='2' height='35' transform="translate(-2, 0)"></rect>
2) Wir könnten dieselbe Transformation über CSS anwenden.
rect:last-of-type {
transform: translateX(-2px); /* Remember this isn't really "pixels", it's a length of 2 in the SVG coordinate system */
}
3) Oder wir könnten kein Prozentzeichen verwenden und sie an einer präzisen Stelle entlang der X-Achse platzieren. Dank des viewBox-Attributs kennen wir das exakte Koordinatensystem von SVG. In Kapitel 6 von Practical SVG erklärt Chris
Die
viewBoxist ein Attribut von<svg>, das das Koordinatensystem und das Seitenverhältnis bestimmt. Die vier Werte sind x, y, Breite und Höhe.
Sagen wir, unsere viewBox ist…
<svg viewBox='0 0 1000 65'>
<!-- the rest of our svg code goes here -->
</svg>
Sie ist also 1000 Einheiten breit. Unsere Markierung ist 2 Einheiten breit. Um die letzte Markierung am rechten Rand zu platzieren, würden wir sie bei 998 platzieren! (1000 – 2). Das wird unser x-Attribut.
<svg viewBox='0 0 1000 65'>
...
<rect fill='#001f3f' x='998' y='0' width='2' height='35'></rect>
...
</svg>
Dies führt dazu, dass unsere Markierung am äußersten rechten Rand des SVG positioniert wird, auch wenn wir es verkleinern.
Juhu! Wir müssen hier kein % oder Pixelwert hinzufügen, da das Koordinatensystem durch die viewBox festgelegt wird.
Nachdem all dies endlich sortiert ist, können wir uns dem nächsten Problem widmen: dem Hinzufügen der %-Beschriftung unter jeder Markierung, um 25 %, 50 % usw. anzuzeigen. Dazu erstellen wir eine neue <g> innerhalb der <svg> und fügen unsere <text>-Elemente hinzu.
<g>
<text fill='#0074d9' x='0' y='60'>0%</text>
<text fill='#0074d9' x='25%' y='60'>25%</text>
<text fill='#0074d9' x='50%' y='60'>50%</text>
<text fill='#0074d9' x='75%' y='60'>75%</text>
<text fill='#0074d9' x='100%' y='60'>100%</text>
</g>
Da wir dies von Hand machen, möchte ich % für den x-Wert verwenden, aber leider wird das dann so aussehen.
Auch hier haben wir ein Problem, dass das letzte Element nicht wie erwartet ausgerichtet ist. Die mittleren Beschriftungen sind ebenfalls falsch platziert; idealerweise wären sie unter ihren Markierungen zentriert. Ich dachte, ich müsste jedes Element mit dem richtigen x-Wert verschieben, bevor Chris mich auf das text-anchor-Attribut aufmerksam machte, von dem ich noch nie gehört hatte.
Mit diesem Attribut können wir den Text ähnlich wie die text-align-Eigenschaft in CSS manipulieren. Diese Eigenschaft wird natürlich vererbt, sodass wir sie einmal auf der <g> setzen und dann die ersten und letzten Elemente ansprechen können.
<g text-anchor='middle'>
<text text-anchor='start' fill='#0074d9' x='0' y='60'>0%</text>
<text fill='#0074d9' x='25%' y='60'>25%</text>
<text fill='#0074d9' x='50%' y='60'>50%</text>
<text fill='#0074d9' x='75%' y='60'>75%</text>
<text text-anchor='end' fill='#0074d9' x='100%' y='60'>100%</text>
</g>
Das wird so aussehen.
Das war's! Mit ein wenig Wissen darüber, wie viewBox funktioniert, zusammen mit x-, y-Koordinaten und Attributen wie text-anchor, können wir mit den Elementen innerhalb eines SVG so ziemlich alles machen.
Indem wir diese Diagramme von Hand erstellen, haben wir das Gefühl, viel Kontrolle zu haben. Es ist nicht schwer vorstellbar, wie wir noch mehr Designkontrolle ausüben oder Daten mit JavaScript einspeisen könnten.
Mit ein wenig zusätzlicher Arbeit können wir diese Diagramme animieren, um sie wirklich hervorzuheben. Versuchen Sie zum Beispiel, über diese Version unseres Diagramms zu fahren.
Ziemlich schick, oder? Und das alles ist mit nur SVG und CSS möglich. Wenn Sie mehr erfahren möchten, habe ich vor einiger Zeit darüber geschrieben, wie man Diagramme mit SVG erstellt, was diese Dinge vertieft erklärt.
Jetzt lasst uns ein paar coole Diagramme erstellen!
Ich dachte, ich versuche mich auch an einer Version!
Siehe den Pen MjNapx von Chris Coyier (@chriscoyier) auf CodePen.
Ich wollte drei Dinge ausprobieren
preserveAspectRatio="none")<line>für die Markierungen anstelle von RechteckenIch wollte auch
vector-effect: non-scaling-stroke;auf diese Linien anwenden, aber ich konnte es in der flüssigen Umgebung nicht herausfinden.Bedeutet, dass die festen Offsets, die Sie in Ihrer
viewBoxverwendet haben, nicht mehr mit der Strichstärke übereinstimmten? Eine einfache Lösung ist, keine festen Offsets oder Positionen zu verwenden. Zeichnen Sie die Linien genau bei 0 % / 100 % und lassen Sie das SVG überlaufen, indem Sie (nicht skalierende) CSS-Polsterung verwenden, um Platz zu schaffen.http://codepen.io/AmeliaBR/pen/a0a4b796d92d4acb9f76e6c316e66b8e/
Aber natürlich, wenn Sie nicht möchten, dass sich die SVG-Striche skalieren oder das Seitenverhältnis beibehalten wird, und da die Höhe fest ist und alle horizontalen Positionen Prozente verwenden, benötigen Sie überhaupt keine
viewBox.http://codepen.io/AmeliaBR/pen/c9ec3eb3d0b35481a74d86c0321d073e/
Gut gemacht! Dieser
text-anchor-Trick ist ziemlich raffiniert. Ich werde also hingehen und ein paar schöne Balken erstellen :)