CSS für Vektordaten

Die Hauptblocktypen

Vektor CSS kennt 3 Geometrietypen:

  • "point": Zur Angabe von Eigenschaften die das Aussehen von Punkten bestimmen
point::PunktId {
    // Eigenschaften des Punktes
}
  • "line": Zur Angabe von Eigenschaften die das Aussehen von Linien bestimmen
line::LinienId {
    // Eigenschaften der Linie
}
  • "polygon": Zur Angabe von Eigenschaften die das Aussehen von Polygonen bestimmen
polygon::PolygonId {
    // Eigenschaften des Polygons
}

Des weiteren gibt es noch "single-choice", "multi-choice" und "settings" Blöcke die weiter unten beschrieben werden.

Zeichenreihenfolge der CSS Blöcke

Im Selektor eines Blocks kann das Schlüsselwort "ordered" bzw. "unordered" angegeben werden. Das Schlüsselwort muss vor dem Geometrietyp, getrennt durch zwei Doppelpunkte oder alleine stehen.

Es gelten die gleichen Vererbungsregeln wie für den Geometrietyp. Ist das Schlüsselwort nicht angegeben oder explizit "unordered" angegeben, so bedeutet dies, das der Block oder die Blöcke in beliebiger Reihenfolge gezeichnet werden dürfen. Ist das Schlüsselwort "ordered" angegeben, so bedeutet dies, das der Block oder die Blöcke in fester Reihenfolge (so wie im CSS definiert) gezeichnet werden müssen. Das "ordered" Schlüsselwort wirkt unabhängig von der Verschachtelungstiefe.

Das Schlüsselwort "ordered" sollte nur, wenn absolut notwendig angegeben werden, da es den Speicherverbrauch erhöht (Geometrien müssen intern zwischengespeichert werden).

CSS-Code kann gleichzeitig sowohl "ordered" als auch "unordered" Blöcke enthalten.

Die folgenden 3 Beispiele sind äquivalent:

ordered {
    line {
        Hauptstraße {
            line-width: 2;
        }

        {
            line-width: 5;
        }
    }
}

Der "Hauptstraße" Block erbt die Schlüsselworte "line" und "ordered" vom übergeordneten Block.

ordered::line {
    Hauptstraße {
        line-width: 2;
    }

    {
        line-width: 5;
    }
}
ordered::line::Hauptstraße {
    line-width: 2;
}

ordered::line {
    line-width: 5;
}

Beispiel für ordered

Im folgenden Beispiel wird die Beschriftung und Füllung für jedes Objekt dieses Datensatzes gezeichnet. Da die Abarbeitung des CSS der Reihe nach für jedes Objekt für jeden Block erfolgt, führt dies zu Überlagerungen von Beschriftung durch die Füllfarbe.

Beispiel Text

polygon {
    fill-color: RGB(128, 128, 128);
    fill-color-opacity: 0.8;
    fill-pattern: solid;
    border-line: {
        line-width: 1px;
        line-color: black;
        line-join: round;
        line-start-cap: round;
        line-end-cap: round;
    };	
}
polygon [mapscale <= 3000] {
    text: [(zaehler) // " / " // (nenner) ];
    text-font-name: "Arial";
    text-color: blue;
    text-height: 20px;
}

Wird das Schlüsselwort "ordered" genutzt, wird für dieses Beispiel zuerst die Flächenfarbe und danach der Beschriftungsblock gezeichnet. Die Beschriftungsinformationen werden für jedes Objekt zwischengespeichert.

Beispiel Text

ordered {
    polygon {
        fill-color: RGB(128, 128, 128);
        fill-color-opacity: 0.8;
        fill-pattern: solid;
        border-line: {
            line-width: 1px;
            line-color: black;
            line-join: round;
            line-start-cap: round;
            line-end-cap: round;
        };	
    }
    polygon [mapscale <= 3000] {
        text: [(zaehler) // " / " // (nenner) ];
        text-font-name: "Arial";
        text-color: blue;
        text-height: 20px;
    }
}

Die Angabe von Defaultwerten

Mit Hilfe des Schlüsselwortes "default" ist es möglich, voreingestellte (Default) Werte für die Eigenschaften von Blöcken festzulegen, die bei neuen Blöcken des entsprechenden Typs verwendet werden, wenn der Block selbst die Eigenschaft nicht definiert.

Das Schlüsselwort "default" muss nach dem Geometrietyp, getrennt durch zwei Doppelpunkte, angegeben werden. Es darf keine BlockId folgen.

Wird das Schlüsselwort "default" verwendet, sind Bedingungen (siehe folgende Beschreibung) und die Schlüsselworte "ordered" und "unordered" im default Block nicht zulässig.

Die Default-Werte haben so lange Bestand, bis sie durch einen neuen Default-Block überschrieben werden.

Ein Default-Wert alleine zeichnet keinen Block. Einschränkung: komplexe Eigenschaften, wie in einer Punktdefinition vorhanden, können nicht in der Symboldefinition überschrieben werden. Damit ist das Nutzen der Default-Werte für Punkte nicht möglich.

Im folgenden Beispiel ist die Default-Linienfarbe ("line-color") rot. Die Linienfarbe für "Hauptstraße" und "Nebenstraße" ist rot (der Default-Wert), da sie die Eigenschaft "line-color" nicht angeben. Die Linienfarbe von "Landstraße" ist hingegen grün.

Durch den zweiten Default-Block wird die Linienfarbe auf schwarz gesetzt, so dass die Linienfarbe von "Schiene" schwarz ist.

line::default {
    line-color: red;
}

unordered {
    line {
        Hauptstraße {
            line-width: 2;
        }

        Nebenstraße {
            line-width: 1;
        }

        Landstraße {
            line-width: 3;
            line-color: green;
        }
    }
}

line::default {
    line-color: black;
}

ordered::line::Schiene {
    line-width: 3;
}

Bedingtes Zeichnen von CSS Blöcken

Blöcke können mit Bedingungen versehen werden, die erfüllt sein müssen, damit ein Block gezeichnet wird. Eine Bedingung wird in eckigen Klammern nach der BlockId geschrieben.

Variablen in einer Bedingung sind hierbei Spaltennamen der Datenquelle.

Im folgenden Beispiel wird die Linie "Hauptstraße" nur dann gezeichnet, wenn die Spalte "Geotyp" den Wert "HS" hat:

ordered {
    line {
        Hauptstraße [Geotyp == "HS"] {
            line-width: 2;
        }

        Landstraße [Geotyp == "LS"] {
            line-width: 5;
        }
    }
}

Eine Variable, die immer definiert ist, ist die Kartenskalierung "mapscale" und mapscale6 (nach der Berechnung wie in Iwan6). Mit Hilfe dieser Variablen können Geometrien abhängig von der Kartenskalierung unterschiedlich gezeichnet werden:

ordered {
    line {
        Hauptstraße_1 [(Geotyp == "HS") && (mapscale <= 10000)] {
            line-width: 2;
        }

        Hauptstraße_2 [(Geotyp == "HS") && (mapscale > 10000)] {
            line-width: 5;
        }
    }
}

Zu Beachten ist, dass Zeichenketten in doppelten Anführungszeichen geschrieben werden müssen.

Folgende Operatoren können in Bedingungen verwendet werden:

Operator Beschreibung
Mathematische Operatoren
+ Addition (a + b)
- Subtraktion (a - b)
* Multiplikation (a * b)
/ Division (a / b)
^ Potenz (a ^ b)
Vergleiche
== Gleichheit (a == b)
!= Ungleichheit (a != b)
> größer als (a > b)
< kleiner als (a < b)
>= größer oder gleich (a >= b)
<= kleiner oder gleich (a <= b)
Vergleiche-Zeichenketten (ab Vers. 7.4.4)
=~ String-Vergleich ohne Beachtung der Groß/Kleinschreibung
~~ Like, ohne Beachtung der Groß/Kleinschreibung, mit % und _ als Platzhalter
!~ Not-Like, ohne Beachtung der Groß/Kleinschreibung, mit % und _ als Platzhalter
Vergleiche mit impliziter Typkonvertierung
=== Gleichheit (a === b)
!== Ungleichheit (a !== b)
>>> größer als (a >>> b)
<<< kleiner als (a <<< b)
>== größer oder gleich (a >== b)
<== kleiner oder gleich (a <== b)
Logische Operatoren
&& logisches und (a && b) -> a und b müssen erfüllt sein
|| logisches oder (a || b) -> a oder b müssen erfüllt sein
String Operationen
// Zeichenketten-Verknüpfungsoperator (a // b) -> Beispiel: [ABC // DEF] ergibt ABCDEF
Sonstige Operatoren
?: if (wenn) then (dann) else (sonst) Operator (a > b ? 10 : 20) -> das Ergebnis ist 10 wenn a größer als b sonst 20

Die Vergleiche mit Werten aus der Datenquelle werden verwendet, wenn der Datentyp der Spalte, zum Zeitpunkt der Erstellung des CSS, unbekannt ist.

Folgendes Beispiel: [PARAM === "1000"]

Ist der Datentyp von PARAM eine Zahl wird die Zeichenkette "1000" in eine Zahl konvertiert und dann mit dem Wert aus PARAM auf Gleichheit getestet. Ist der Datentyp von PARAM hingegen eine Zeichenkette, werden die beiden Zeichenketten direkt auf Gleichheit getestet.

Folgende Funktionen können in Bedingungen verwendet werden:

Funktion Beschreibung
FirstChar(a) Extrahiert den ersten Buchstaben aus einer Zeichenkette (a). Der Rückgabewert ist eine Zeichenkette. Beispiel: [FirstChar(LABEL)]
SubStr(a, b, c) Extrahiert eine Anzahl (c) Zeichen bei Startposition (b) des Eingabestrings (a). Das erste Zeichen hat die Startposition (b) 0. Der Rückgabewert ist eine Zeichenkette. Beispiel: [SubStr(LABEL, 0, 3)]
ToString(a) Konvertiert die Eingabe (a) in einen String. Die Eingabe (a) kann eine Zahl oder ein String sein. Der Rückgabewert ist eine Zeichenkette. Beispiel: [ToString(PARAM1)]
ContainsString(a, b) Gibt true zurück wenn die Zeichenkette (a) die Zeichenkette (b) enthält. Der Vergleich ist Case-Sensitiv. Beispiel: [ContainsString(GEOTYP, "ef")]
IsNull(a) Gibt true zurück wenn die Spalte leer ist. Beispiel: [IsNull(Label) ? "keine Angabe" : Label]
min(a,b) gibt den kleineren der beiden numerischen Werte zurück.
max(a,b) gibt den größeren der beiden numerischen Werte zurück.
AnyInteger(int,const) *1) Prüft, ob der Ganzzahlwert int in der Liste der Werte const enthalten ist
AnyDouble(double,const) ... für Fließkommazahlen
AnyString(string,const) ... für Texte

*1 Die AnyXXXX Funktionen erwarten als erstes Argument einen dynamischen Wert (d.H. bspw. aus einer Spalte) und als zweites Argument eine Zeichenfolge die kommagetrennt die zu vergleichenden Werte enthält.

Bei der ersten Ausführung wird diese Werteliste intern in eine effiziente Hash-Tabelle konvertiert.

Bei Zeichenketten wird Groß/Kleinschreibung unterschieden, die Werte können kein Komma enthalten. Bei Fließkommazahlen ist der Dezimalpunkt zu verwenden.

Bsp.: [AnyString(ordn,"1,2,AR")]

Die Reihenfolge der Abarbeitung der Operatoren kann mit runden Klammern gesteuert werden.

Zu beachten ist, dass eine Bedingung am Ende einen logischen Ausdruck ergeben muss, der entweder wahr oder falsch sein kein.

Bedingungen können auch geschachtelt werden. Das kann die Performance verbessern, wenn dadurch mehrere Sub-Blöcke nicht getestet werden müssen.

Im folgenden Beispiel werden "Hauptstraße_1" und "Landstraße_1" gezeichnet, wenn die Kartenskalierung kleiner oder gleich 1:10000 ist:

unordered {
    line {
        [mapscale <= 10000] {
            Hauptstraße_1 [Geotyp == "HS"] {
                line-width: 4;
            }

            Landstraße_1 [Geotyp == "LS"] {
                line-width: 2;
            }
        }

        [mapscale > 10000] {
            Hauptstraße_2 [Geotyp == "HS"] {
                line-width: 10;
            }

            Landstraße_2 [Geotyp == "LS"] {
                line-width: 5;
            }
        }
    }
}
Optimierung von Bedingungen

Im Zusammenhang mit Bedingungen gibt es den sogenannten "single-choice" bzw. "multi-choice" Block.

Diese Blöcke kapseln mehrere Blöcke mit Bedingungen und stellen sicher, das maximal ein Block, dessen Bedingung zutrifft, gezeichnet wird, selbst wenn es weitere Blöcke gibt, deren Bedingung wahr ist. Der Unterschied zwischen einem "single-choice" und einem "multi-choice" Block ist das bei einem "single-choice" Block mit dem nächten Datensatz fortgefahren wird sobald die Bedingung eines Blocks zutrifft selbst wenn dieser Block leer ist und nichts gezeichnet wurde. Der "multi-choice" Block hingegen geht potentiell alle Blöcke deren Bedingung zutrifft durch und fährt mit dem nächsten Datensatz fort sobald tatsächlich etwas gezeichnet wurde oder alle Blöcke durchgegangen wurden.

Der "single-choice" bzw. "multi-choice" Block sollte wenn immer möglich verwendet werden. Die Performance kann deutlich steigert werden, da die Anzahl der Bedingungsauswertungen drastisch reduziert wird.

unordered {
    line {
        single-choice {
            Hauptstraße [Geotyp == "HS"] {
                line-width: 2;
            }

            Landstraße [Geotyp == "LS"] {
                line-width: 5;
            }
        }
    }
}

Zu beachten ist, dass ein "single-choice" bzw. "multi-choice" Block keine BlockId definieren darf und selbst auch keine Eigenschaften definiert.

Eine weitere Optimierung ist die Erzeugung eines Filters aus den Bedinungen der CSS Blöcke, der dann auf die Datenquelle angewendet wird. Dadurch werden nur die Datensätze abgerufen, die auch gezeichnet werden. Die Erstellung des Filters geschieht intern automatisch. Dies kann die Performance deutlich verbessern aber in bestimmten Szenarien kann auch das Gegenteil der Fall sein. Deshalb gibt es den "settings" Block, der die Eigenschaft "allow-query-optimization" hat. Damit lässt sich steuern ob intern ein Filter erzeugt wird oder nicht.

Im folgenden Beispiel wird ein Filter erstellt, der dafür sorgt das nur Datensätze von der Datenquelle geliefert werden, bei dem die Spalte "Geotyp" entweder den Wert "HS" oder "LS" hat.

unordered {
	line {
		single-choice  {     
			settings {
				allow-query-optimization: true;
			}       

			Hauptstraße1 [Geotyp == "HS"]{
				line-width: 2;
			}

			Landstraße1 [Geotyp == "LS"] {
				line-width: 5;
			}
		}
	}
}
Eigenschaftsausdrücke

Neben Bedingungen gibt es noch Ausdrücke, die ausgewertet werden.

Ausdrücke werden in eckigen Klammern, nach dem Eigenschaftsnamen und folgenden Doppelpunkt geschrieben und ersetzen die direkte Wertzuweisung.

Mit Ausdrücken ist es möglich, Werte aus der Datenquelle mit ins Style einfließen zu lassen. Ausdrücke verwenden die gleichen Operatoren wie Bedingungen, haben jedoch einen wesentlichen Unterschied: Das Ergebnis eines Ausdrucks muss vom Typ der Eigenschaft sein.

unordered::line::Hauptstraße [Geotyp == "HS"] {
    // Linienbreite ist 10 Meter plus 4 Pixel
    line-width: [MeterToPixel(10.0)+4]; 
    // Text kommt aus der Datenquelle (Spalte: LABEL)
    text: [LABEL]; 
    // Textfarbe ist Schwarz wenn PARAM1 gleich 3 sonst Blau
    text-color: [PARAM1 == 3 ? "black" : "blue"]; 
}

In Ausdrücken können folgende Funktionen verwendet werden:

Funktion Beschreibung
MeterToPixel(a) Konvertiert eine Meterangabe (a) in Pixel. Ist a ein direkt angegebener Wert, so darf er keine Einheit haben. Der Rückgabewert ist eine Zahl. Beispiel: [MeterToPixel(PARAM1)]
FirstChar(a) Extrahiert den ersten Buchstaben aus einer Zeichenkette (a). Der Rückgabewert ist eine Zeichenkette. Beispiel: [FirstChar(LABEL)]
SubStr(a, b, c) Extrahiert eine Anzahl (c) Zeichen bei Startposition (b) des Eingabestrings (a). Das erste Zeichen hat die Startposition (b) 0. Der Rückgabewert ist eine Zeichenkette. Beispiel: [SubStr(LABEL, 0, 3)]
ToString(a) Konvertiert die Eingabe (a) in einen String. Die Eingabe (a) kann eine Zahl oder ein String sein. Der Rückgabewert ist eine Zeichenkette. Beispiel: [ToString(PARAM1)]
ContainsString(a, b) Gibt true zurück wenn die Zeichenkette (a) die Zeichenkette (b) enthält. Der Vergeleich ist Case-Sensitiv. Beispiel: [ContainsString(GEOTYP, "ef")]
IsNull(a) Gibt true zurück wenn die Spalte leer ist. Beispiel: [IsNull(Label) ? "keine Angabe" : Label]
Printf(format,...args) Formatiert eine Zeichenfolge mit einer c ähnlichen Syntax. Beispiel:
[Printf("%.2f €\nStand: %i",COL1,COL2)]

Zu unterscheiden sind zwei Typen von Ausdrücken:

  • Konstante Ausdrücke haben keine Variablen mit Ausnahme von "mapscale" /"mapscale6" und werden nur einmal ausgewertet, da das Ergebnis konstant ist.
  • Variable Ausdrücke haben Variablen aus der Datenquelle und werden mit jedem Datensatz aus der Datenquelle neu ausgewertet, was von der Performance her sehr teuer ist. Sie sollten daher nur, wenn absolut notwendig, verwendet werden.
Erstellung einer Kartenlegende

Ein weiterer Spezialblock für Vektordaten ist der "map_legend" Block. Er dient der manuellen Erstellung einer Kartenlegende.

Dieser Block darf nicht in einem anderen Block vorkommen und sollte am Ende des CSS angegeben werden.

Jeder Block innerhalb des "map_legend" Blocks definiert einen Eintrag in der Kartenlegende und darf eine BlockId haben.

Eine Beschreibung zu dem Element und weitere Details, sowie Informationen zur automatischen Legendenerstellung, sind unter Kartenlegenden für Vektor-Stile beschrieben.

Mit der Eigenschaft "exclude-from-map-legend" eines Symbols (Punkt, Linie, Polygon), ist es möglich ein Symbol vom Zeichnen in die Kartenlegende auszuschließen.

Syntax bestimmter Eigenschaften

Im Vektor-Daten CSS gibt es einige besondere Eigenschaften, die eine spezielle Syntax aufweisen.

Die Eigenschaften "outer-border-line", "inner-border-line" und "border-line" der Entität "polygon" bekommen als Wert einen anonymen "line" Block ohne Selektor (Selektor ist implizit "line"). Innerhalb dieses Blocks sind alle Eigenschaften erlaubt, die für die "line" Entität zulässig sind. Der "line" Block muss mit einem Semikolon abgeschlossen werden.

unordered::polygon {
    outer-border-line:
    {
        line-width: 3px;
        line-color: black;
    };
    inner-border-line:
    {
        line-width: 3px;
        line-color: yellow;
    };
}
unordered::polygon {
    border-line:
    {
        line-width: 3px;
        line-color: black;
    };
}

Die Eigenschaft "complex-fill-pattern" der Entität "polygon" und die Eigenschaft "complex-graphics" der Entität "point" bekommen als Wert eine durch Komma getrennte Liste von Blöcken. Diese ist wie das komplexe Muster bzw. der Punkt zu zeichnen. Die einzelnen Blöcke müssen einen Blocktyp definieren und können eine BlockId haben. Diese BlockId kann nicht in einer Kartenlegende verwendet werden. Der letzte Block muss mit einem Semikolon abschließen.

unordered::point::id0 {
    complex-graphics:
        arc::id1 {
            line-width: 2px;
            line-color: black;
            position-x: 0;
            position-y: 0;
            radius: 20px;
            start-angle: 0;
            sweep-angle: 360;
        },
        text::id2 {
            text: [FirstChar(LABEL)];
            text-color: black;
            text-font-name: "Arial";
            text-height: 20px;
            text-weight: 400;
            text-quality: antialiased;
            text-horizontal-alignment: center;
            text-vertical-alignment: center;
            position-x: 0;
            position-y: 0;
        };
}
Sichtbarkeit der CSS Symbole

Damit CSS Symbole auch dann sichtbar sind wenn ihre Geometrie bereits außerhalb der BoundingBox des Bildschirms ist, muss diese BoundingBox für die Abfrage um die Ausdehnung des größten CSS Symbols erweitert werden. Dies ist insbesondere notwendig beim Druck, da dort die Karte aus mehreren Kacheln zusammengesetzt werden kann, um das Abschneiden von CSS Symbolen an den Kachelübergängen zu verhindern. Ein Problem tritt auf wenn ein CSS Symbol variable Ausdrücke (Ausdrücke mit Spaltennamen) enthält. In diesem Fall werden, bei der Berechnung der maximalen Ausdehnung des CSS Symbols, festgelegte Pixelgrößen für die CSS Eigenschaft verwendet. Folgende Pixelgrößen werden verwendet:

  • Der Pufferabstand bei gepufferten Geometrien beträgt 20 Pixel
  • Alle Positionsangaben sind 50 Pixel
  • Der Radius von arc und circle beträgt 20 Pixel
  • Die Höhe von komplexen Füllmustern bei Linien beträgt 40 Pixel
  • Der Offset bei Linien beträgt 20 Pixel
  • Der Radius des Kreises und die Pfeillänge bei der Start/End-Geometrie von Linien beträgt 20 Pixel
  • Sowohl der X als auch der Y Abstand vom Einfügepunkt von Punkten von line, polygon und polyline (complex-fill-pattern bzw. complex-graphics) beträgt 100 Pixel
  • Die Dicke von Linien beträgt 10 Pixel
  • Die Höhe und Breite eines pixmap beträgt 200 Pixel
  • Die Höhe und Breite eines path beträgt 100 Pixel
  • Die Texthöhe beträgt 30 Pixel

Sonstige festgelegte Größen:

  • Die Anzahl der Zeichen bei Text beträgt 20
  • Die Anzahl der Zeilenumbrüche bei Text beträgt 3
Hinweise zur Maßstabsbeschränkung von Symboliken

Bei der Berechnung der Maßstabszahl mit IWAN7 Ebenen wird intern der OGC MapScale verwendet. Dabei kommt es zu einer Differenz (bei einer Beschränkung bis einem Maßstab <= 10000 werden die Symboliken von Iwan7 Ebenen nur bis zum Maßstab <= 8950 gezeichnet), welche aber durch die Angabe von Faktoren bei der Definition des Maßstabsbereiches im css-Style auszugleichen ist. D.h. bei einer Beschränkung des Zeichenbereichs auf einen Maßstab von bspw. mapscale <= 10000 ist hier folgender Faktor zu notieren: mapscale <= 10000*(0.3125/0.28). Das entspricht mapscale <= 11161.

Alternativ steht die Konstante mapscale6 zur Verfügung, hier wird der Maßstab wie von Iwan6 berechnet hinterlegt.

Der Faktor kommt durch folgende Angaben zustande:

Verhältnis:

0.3125 -=> Größe eines Pixels bei ca. 81 dpi Ausgabe am Bildschirm

0.28 => Größe eines Pixel bei ca. 91 dpi Ausgabe am Bildschirm

Dies gilt für alle IWAN7 Ebenen zu beachten.


Zuletzt geändert: 05.10.2020 17:05:21 (erstmals erstellt 24.08.2018)