Download-Icon

download-icon.html

Der angebenen Downloaddatei wird, basierend auf deren Dateiendung, ein passendes Icon zugeordnet.

<svg
   xmlns = "http://www.w3.org/2000/svg"
   width = "48"
   height = "48"
   viewBox = "0 0 512 512"
>
   <!-- Disk body -->
   <polygon
      id = "shape"
      points = "0,0 512,0 512,512 50,512 0,462"
      style = "fill: #0000ff;
               fill-opacity: 1;
               stroke: #000080;
               stroke-width: 2;
               stroke-opacity: 1;"
   />
   <rect
      id = "slideway"
      width = "320"
      height = "168"
      x = "136"
      y = "344"
      style = "fill: #0000f0;
               fill-opacity: 1;
               stroke: #000000;
               stroke-width: 2;
               stroke-opacity: 1;"
   />
    <rect
      id = "slider"
      width = "220"
      height = "200"
      x = "138"
      y = "346"
      rx = "20"
      ry = "20"
      style = "fill: #c0c0c0;
               fill-opacity: 1;
               stroke: none;"
   />
   <rect
      id = "slider slot"
      width = "60"
      height = "120"
      x = "164"
      y = "364"
      style = "fill: #0000f0;
               fill-opacity: 1;
               stroke: none;"
   />
   <!-- Disk label -->
   <rect
      id = "label"
      width = "400"
      height = "300"
      x = "56"
      y = "2"
      style = "fill: #ffffff;
               fill-opacity: 1;
               stroke: #808080;
               stroke-width: 2;
               stroke-opacity: 1;"
   />
   <line
      id = "topmost label line"
      x1 = "68"
      y1 = "70"
      x2 = "444"
      y2 = "70"
      style = "stroke: #000000;
               stroke-opacity: 1;
               stroke-width: 3;"
   />
   <line
      id = "mid label line (below the text)"
      x1 = "68"
      y1 = "230"
      x2 = "444"
      y2 = "230"
      style = "stroke: #000000;
               stroke-opacity: 1;
               stroke-width: 3;"
   />
   <line
      id = "lowest label line"
      x1 = "68"
      y1 = "280"
      x2 = "444"
      y2 = "280"
      style = "stroke: #000000;
               stroke-opacity: 1;
               stroke-width: 3;"
   />
   <text
      id = "label imprint"
      x = "68"
      y = "180"
      style = "font-style: normal;
               font-variant: normal;
               font-weight: bold;
               font-stretch: normal;
               font-size: 7rem;
               font-family: Work Sans, Helvetica, Tahoma, Geneva, Arial, sans-serif;
               font-variant-ligatures: normal;
               font-variant-caps: normal;
               font-variant-numeric: normal;
               font-feature-settings: normal;
               text-align: start;
               writing-mode: lr-tb;
               text-anchor:start;"
   >
      <!-- Label text goes here, max. 5 glyphs, or 4 ems "MMMM"! -->
      <!-- Attention: countrunes still gets the leading '.' if there is any! -->
      <!-- This is why the '(none)' is given even if we one rune. -->
      {{- $fext := path.Ext .Params.file -}}
      {{- if gt (countrunes $fext) 1 -}}
         <!-- Remember the very first rune is the '.'! So we take just 5 -->
         <!-- runes as the file type. If more than those it will get -->
         <!-- truncated to four runes plus the ellipsis -->
         {{- if le (countrunes $fext) 6 -}}
            {{- delimit (first 1 (findRE "[^(.)].{0,4}" $fext)) " " -}}
         {{- else -}}
            {{- delimit (first 1 (findRE "[^(.)].{0,3}" $fext)) " " -}}
            &#8230; <!-- ellipsis -->
         {{- end -}}
      {{- else -}}
         (none)
      {{- end -}}
   </text>
</svg>

Wie man sieht, ist das Icon als SVG definiert.

Zunächst wird das SVG eingeleitet:

<svg
   xmlns = "http://www.w3.org/2000/svg"
   width = "48"
   height = "48"
   viewBox = "0 0 512 512"
>

<svg> zeigt dem Browser an, dass nun eine Grafikdefinition gemäß SVG-Standard folgt. Dabei werden im tag einige Attribute mitgegeben. xmlns = "http://www.w3.org/2000/svg" wäre, dem SVG-Standard folgend, gar nicht erforderlich. Beim Experimentieren mit Firefox (69.0.3) hat sich allerdings gezeigt, dass ohne diese Zeile das SVG nicht erzeugt wird. Schädlich ist es nicht und so bleibt es als “Browser-Workaround” im Script. (Siehe eventuell unsere Diskussion zum xmlns.)

width = "48" legt die gewünschte Breite auf der Seite fest. Die Einheit ist Pixel. height = "48" definiert baugleich die Höhe des Icons. viewBox = "0 0 512 512" hingegen gibt die Größe der Zeichenfläche an. Auf diese Zeichenfläche werden gleich die einzelnen Elemente gezeichnet und positioniert.

Als Icon soll eine stilisierte 3.5”-Diskette erscheinen. Der Grundkörper ist 5-seitig - zunächst ein Quadarat, bei dem links unten eine Ecke abgeschnitten ist. Der Grundkörper nutzt die Zeichenfläche voll aus.

   <polygon
      id = "shape"
      points = "0,0 512,0 512,512 50,512 0,462"
      style = "fill: #0000ff;
               fill-opacity: 1;
               stroke: #000080;
               stroke-width: 2;
               stroke-opacity: 1;"
   />

<polygon leitet die Sequenz ein. Die Angabe einer id ist optional, es geht auch ohne. Hier wird sie als Orientierungshilfe verwendet, um die Teile besser identifizieren zu können. points definiert nun die Punktliste, die das Polygon auf seinen Ecken trifft. Jeder Punkt besteht aus den Koordinaten x,y. Links oben im Ursprung (0,0) beginnt der Umriss, geht horizontal nach rechts oben (512,0), von dort aus vertikal nach unten (512,512 - man beachte das Vorzeichen der y-Richtung!) und wieder nach links, allerdings nicht ganz bis zum Anschlag (50,512). Von diesem Punkt aus geht es diagonal zum Punkt 0,462 (462 = 512-50), das ergibt einen 45°-Winkel. Der Polygonzug wird automatisch vom letzten angegeben Punkt zum Startpunkt geschlossen.

style = "" eröffnet die Formatierung bezüglich des Aussehens. fill: #0000ff; füllt das Polygon blau. fill-opacity: 1; sorgt für opaque Füllung (keine Transparenz). stroke: #000080; färbt den Rand des Polygons dunkelblau. stroke-width: 2; gibt die Breite des Randes vor. stroke-opacity: 1; entzieht auch dem Rand jede Transparenz.

Nachdem der Grundkörper definiert ist, folgen die weiteren Elemente:

  • Mulde für den Schieber (<rect id = "slideway")
  • Der Schieber (<rect id = "slider") mir runden Ecken
  • Der Ausbruch im Schieber (<rect id = "slider slot")
  • Das weiße Etikett (<rect id = "label")
  • Drei angedeutete Beschriftungslinien (<line id = "topmost label line"), (<line id = "mid label line (below the text)") und (<line id = "lowest label line")
  • Die Beschriftung (<text id = "label imprint")

Dabei werden die Elemente der Reihe nach “gezeichnet”, bei Überlappung werden vorher definierte Elmente überdeckt. Gehen Element über die Grenzen des viewport hinaus, werden die betreffenden Teile abgeschnitten.

Die Finessen der einzelnen Zeichnungselemente (rect, line, text) beschreibt das w3schools-Tutorial. An dieser Stelle sei darauf verwiesen.

Als Beschriftung wird die Dateiendung des Download-Files verwendet. Schritt für Schritt:

      {{- $fext := path.Ext .Params.file -}}

Der Dateiname wird durch .Params.file angeliefert. (path.Ext) holt die Endung des Dateinamens (alles hinter und mit dem letzten ‘.') dort heraus. Die Dateiendung wird in der Variablen $fext aufbewahrt. Von der /ftpedia/2019/2019-3/ftpedia-2019-3.pdf bliebe .pdf übrig. Aber die ft:pedien werden speziell und besonders behandelt.

Dateiendungen sind nun nicht auf exakt drei Zeichen festgelegt. Diesem Umstand wird durch Fallunterscheidungen Rechnung getragen. Zunächst wir mal nachgeschaut, ob es überhaupt eine Dateiendung gibt. Wenn ja gibt es mehr als ein Zeichen. Man denke bitte an den Punkt, der alleine stehen könnte! Anderenfalls wird im Icon der Text (none) erscheinen.

{{- if gt (countrunes $fext) 1 -}}
   ...
{{- else -}}
   (none)
{{- end -}}

Ist die Hürde der Dateiendung genommen, also es gibt irgendeine Zeichenkette, muss deren Länge sinnvoll begrenzt werden. Unterlässt man das, sieht das Icon “schlecht” aus, weil der Text über das Etikett hinausgeht. Außerhalb des SVG-viewport wird auch der Text beschnitten und nicht dargestellt. Maximal passen vier Em (‘MMMM’) auf das Etikett. In der Regel können jedoch bis zu fünf Zeichen dargestellt werden. Auf diese 5 Zeichen ist die Beschränkung ausgelegt. Ist die Zeichenkette kurz genug, wird die Dateiendung in voller Länge, aber ohne ‘.’ auf das ‘Etikett’ gebracht. Ist die Zeichenkette länger, wird ebenfalls der Punkt rausgeworfen, aber nur die ersten 4 Zeichen der Dateiendung übernommen. Der abgeschnittene Rest wird durch ein ‘Ellipsis’ dargestellt.

{{- if le (countrunes $fext) 6 -}}
   {{- delimit (first 1 (findRE "[^(.)].{0,4}" $fext)) " " -}}
{{- else -}}
   {{- delimit (first 1 (findRE "[^(.)].{0,3}" $fext)) " " -}}
   &#8230; <!-- ellipsis -->
{{- end -}}

Die Definition des Textes und des SVG endet regulär mit

   </text>
</svg>

Auf diese Art bekommen wir eine blaue Diskette mit weißem Etikett. Die ‘Beschriftung’ stellt sich automatisch auf die angebotene Download-Datei ein. Es entfällt jeglicher Aufwand ein bestimmtes Icon für eine bestimmte Dateiendung zu erzeugen (z. B. png-Bilddatei), per Script zuzuordnen und zu pflegen.

Das erzeugte Download-Icon wird überall und unabhängig vom Browser gleichmässig dargestellt.

Versuche eine Bilddatei mit leerem Etikett zu nehmen und die Dateiendung per css darüber zu legen sind gescheitert. Der alte Ansatz mit einer Bilddatei für jede bekannte Dateiendung ist wegen des Aufwandes inakzeptabel.

Stand: 25.Oktober 2019