Kapitel 5: Auf dem Server zeichnen
go get gitlab.com/mlc0911/mlctimegraph/go-time-graphDie Go-Seite hat drei Einsatzzwecke, und die Wahl hängt davon ab, wo das Bild entsteht.
Als Bibliothek
Im eigenen Dienst, wenn das Diagramm Teil einer größeren Antwort ist — ein Bericht, eine Seite, ein Anhang.
Zwei Dinge zählen, wenn das SVG neben anderen landet — mehrere Diagramme in
einer HTML-Seite oder einem Bericht. Setze idPrefix in den Optionen, wie im
Browser, und die eigenen ids des Renderers (Verläufe, Muster, Beschneidungspfade
in <defs>) mit SetIDPrefix:
r := renderer.NewSVGRenderer("800", "400")
r.SetIDPrefix(opts.IDPrefix) // etwa "keller"Und die Auswertung, die zum Bild gehört, läuft hier ebenfalls:
analyze.ComputeLimitExcursions liefert dieselben Episoden und dieselbe Zeit
außerhalb der Grenzen wie computeLimitExcursions im Browser — Bildschirm und
PDF nennen also dieselbe Dauer.
In Go bekommt eine Wertachse ihr eigenes Zahlenformat im Code, denn eine Funktion reist nicht
als JSON. YAxisConfig.Format ist das Gegenstück zu axes.y[].format im Browser:
opts.Axes.Left.Format = func(v float64) string { return fmt.Sprintf("%.1f °C", v) }Als Kommandozeilenwerkzeug
graph-cli -in config.json -out chart.svg
graph-cli -in config.json -out chart.svg -bg whiteFür zeitgesteuerte Aufgaben: der tägliche Bericht um sechs, das wöchentliche Bild
am Montag. -bg white setzt einen Hintergrund — nötig, sobald das Bild in ein
PDF oder eine E-Mail eingebunden wird, wo Transparenz schnell zu Schwarz auf
Schwarz werden kann.
Jede statische Abbildung in diesem Handbuch entstand auf diesem Weg.
Das Wiederkehrende in eine eigene Datei
Sobald mehrere Berichte entstehen, wiederholt sich ein Teil der Beschreibung:
Maße, Achsen, Legende, Farben. Diesen Teil in jede Datei zu kopieren heißt, ihn
irgendwann an zwölf Stellen zu ändern und an einer zu vergessen. -with legt
ihn stattdessen darüber:
graph-cli -in messwerte.json -with haus-theme.json -out chart.svgDas Flag ist wiederholbar, die spätere Ebene gewinnt — so lässt sich ein Hausstil um Projekt- und Einzelfall-Abweichungen ergänzen:
graph-cli -in messwerte.json -with haus-theme.json -with bericht.json -out chart.svgDie Regel dahinter ist ein Satz: Objekte verschmelzen, alles andere wird ersetzt. Ein Theme, das nur das Gitter setzt, lässt die Achsenbeschriftung aus den Daten stehen:
{
"width": 1000,
"axes": {
"x": { "grid": { "major": { "color": "#eeeeee" } } },
"left": { "grid": { "major": { "color": "#eeeeee" } } }
},
"legend": { "show": true, "position": "outside-right" }
}„Alles andere" schließt Arrays ein, und das ist die Stelle, an der man
aufpassen muss: Eine Ebene mit series ersetzt die Messreihen, statt sie zu
gestalten. Das ist Absicht — würde angehängt, machte ein Theme mit einem
einzigen Linienstil aus einer Kurve zwei, und niemand käme darauf, warum. Die
CLI warnt, wenn eine überlagernde Ebene series setzt.
mtg-pdf kennt dasselbe Flag. Dort gilt es nur für Optionen: Zeichenbefehle
sind bereits gerechnete Geometrie, über die sich kein Theme legen lässt.
Im Browser leistet mergeOptions dasselbe:
import { mergeOptions, MLTimeGraph } from 'ml-time-graph';
new MLTimeGraph(mergeOptions(hausTheme, messwerte));Nicht zu verwechseln mit { ...hausTheme, ...messwerte } — der Spread ist
flach. Ein axes im zweiten Objekt ersetzt damit das komplette axes des
ersten, samt Gitter und Ticks.
Als HTTP-Dienst
graph-server nimmt dieselbe JSON-Beschreibung entgegen und antwortet mit SVG.
Sinnvoll, wenn mehrere Anwendungen Diagramme brauchen und keine davon eine
Go-Abhängigkeit aufnehmen soll.
Die Beschreibung
Alle drei lesen dieselbe Struktur — genau die, die auch die TypeScript-Seite im Browser akzeptiert. Ein Diagramm, das du interaktiv entworfen hast, wird zu einer JSON-Datei und läuft unverändert durch den Server.
Wenn die Beschreibung falsch ist
Ein Tippfehler in einer JSON-Datei verschwand früher spurlos: "lnie": "dashed"
wurde übergangen, der Schwellenwert kam durchgezogen heraus, und niemand wusste,
warum. Seit 1.17 prüfen alle drei Zugänge jedes Feld gegen die Beschreibung und
lehnen ab, was sie nicht kennen:
invalid options: legnd: unknown field (did you mean "legend"?);
thresholds[0].lnie: unknown field (did you mean "line"?)Alle Fehler in einer Meldung, jeder mit seinem Pfad, mit Vorschlag, wo ein
bekannter Name nahe liegt. Fehlende Pflichtfelder — eine Reihe ohne name oder
data, ein Schwellenwert ohne name — werden genauso gemeldet. Die CLI endet
mit Fehler, graph-server antwortet 400, und chart.LoadOptions gibt den
Fehler an deinen Code zurück.
Und was kein Fehler ist
Manche Beschreibung ist vollständig und trotzdem nicht gemeint: ein Schwellenname mit
Tippfehler in colorByThresholds, eine Flächengrenze, die eine Reihe nennt, die es nicht gibt,
side an einer Fläche, die es nicht beachtet. Gezeichnet wird trotzdem, nur ohne die Zone.
Beide Bibliotheken melden solche Fälle auf Nachfrage, mit demselben Text:
for _, w := range chart.NewMLTimeGraph(opts).Warnings() {
log.Println(w) // series 0 colorByThresholds names unknown threshold "mxa"
}Im Browser heißt es chart.warnings(). Schwellenwerte werden über ihre id gesucht und nur
ohne id über den name, genau wie beim Zeichnen: Ein Schwellenwert mit id ist unter seinem
Namen nicht zu finden, und der Hinweis sagt das.
Was der Server nicht kann
Alles, was jemand anklickt. Kein Zoom, kein Tooltip, keine Auswahl. Wenn du das brauchst, brauchst du den Browser — und wenn nicht, spart dir der Server eine Runtime, eine Fehlerklasse und einen Seitenaufruf.