Zum Inhalt springen
EcoSimLab
DeutschEnglish
Docs-Navigation
Tool-Docs

EcoInterfaces

Die Display-Bibliothek installieren, einen DisplayInput bauen, ein Display rendern, das Stylesheet laden und den passenden Export finden.

Gehört zu: EcoInterfaces

Diese Seite ist die Anleitung zur Display-Bibliothek @ecosimlab/ecodisplays. Sie beschreibt Installation, Eingabevertrag, Exporte und Stylesheet. Wozu die Bibliothek gut ist, steht auf der Tool-Seite.

Alle Angaben sind aus dem Repo ecodisplays belegt, Branch main (Commit 94b20a3), Paketversion 1.0.2, neuester Tag v1.0.2. Wo README und Code auseinanderlaufen, gilt der Code, und diese Seite benennt die Abweichung.

Die Bibliothek zeichnet Displays. Sie spricht weder mit einem Simulator noch mit einem Broker noch mit dem Netz. Die Daten bringt der Konsument mit.

Voraussetzungen

  • Ein Bundler für SolidJS. Das Paket liefert übersetztes JSX als ES-Module. Ein Vite-Projekt mit vite-plugin-solid ist der geprüfte Fall.
  • Drei Peer-Dependencies: solid-js 1.9, d3 7 und lodash 4.17. Das Paket deklariert sie, installiert sie aber nicht mit.
  • Genau eine Kopie von solid-js je Seite. Zwei Kopien zerstören die Reaktivität. Den Bundler notfalls auf eine Kopie festlegen.
  • Node oder Bun mit einem Paketmanager für die Installation. Das Paket deklariert kein engines-Feld.

Installation

Das Paket liegt in keiner Registry. Es kommt aus dem öffentlichen GitLab-Repo, festgenagelt auf einen Tag. Das gebaute dist/ liegt im Repo, die Installation baut also nichts. Token und .npmrc sind nicht nötig.

Mit npm:

npm install gitlab:ecosimlab/ecodisplays#v1.0.2

Mit bun, als Eintrag in den Abhängigkeiten:

"dependencies": {
  "@ecosimlab/ecodisplays": "git+https://gitlab.com/ecosimlab/ecodisplays.git#v1.0.2"
}

Immer genau einen Tag festnageln, nie einen Branch.

Das README nennt in beiden Beispielen noch v0.5.0. Die package.json von main trägt Version 1.0.2, und v1.0.2 ist der neueste Tag. Es gilt die Version im Code.

Quickstart

Das kleinste vollständige Beispiel: ein Display, eine Eingabe, ein Stylesheet.

import { createSignal } from "solid-js"
import { AP6DefaultDisplay, displayInput } from "@ecosimlab/ecodisplays"
import "@ecosimlab/ecodisplays/styles.css"

export function Screen() {
  const [input] = createSignal(
    displayInput({ hasSimulationData: true, speedKmh: 48, gear: "D" }),
  )

  return (
    <div style={{ width: "640px", height: "400px" }}>
      <AP6DefaultDisplay input={input()} fit="contain" />
    </div>
  )
}

Jedes Display nimmt dieselben zwei Props:

Prop Bedeutung
input der aktuelle DisplayInput
fit wie das Display seine Elternbox füllt: "contain" (Vorgabe) passt den ganzen Entwurf in die Box ein, "width" lässt die Breite führen

InputTransparenzDisplay nimmt eine weitere Prop, vehiclesAheadMode, ohne Vorgabe. Sie wird auf "all" oder auf "closest" gesetzt. Dasselbe Display nimmt die optionale Prop signsMode mit der Vorgabe "list"; sie legt fest, wo die Schilder stehen.

Paket-Exporte

Die package.json deklariert vier Einstiege.

Einstieg Inhalt
@ecosimlab/ecodisplays die 20 Displays, DisplayInput, displayInput, defaultDisplayInput, VehicleProfile, InputPanel, DisplayFrame, die Design-Größen und die reinen Rechenfunktionen
@ecosimlab/ecodisplays/input nur der Eingabevertrag: DisplayInput, displayInput, defaultDisplayInput, INPUT_FIELDS, deriveDisplayGate, VehicleProfile. Lädt weder SolidJS noch das DOM.
@ecosimlab/ecodisplays/styles.css das Stylesheet als Datei
@ecosimlab/ecodisplays/styles dasselbe Stylesheet als Strings css und fontFaceCss

./input ist der Einstieg für einen Parser oder einen Test, der in reinem Node oder Bun laufen muss.

Der Eingabevertrag

DisplayInput ist ein flaches Objekt mit 31 Feldern. Die Bibliothek prüft zur Laufzeit keinen Wert. Der Vertrag ist der Typ, die Prüfung gehört an die Grenze des Konsumenten.

Eine Eingabe baut displayInput(partial). Jedes ausgelassene Feld kommt aus defaultDisplayInput:

import { type DisplayInput, displayInput } from "@ecosimlab/ecodisplays/input"

const input: DisplayInput = displayInput({
  hasSimulationData: true,
  hasEnergyData: true,
  timeS: 12.5,
  wheelspeedMps: 13.3,
  batterySocPercent: 72,
})

Die Einheit steht im Namen

Jeder Feldname endet auf seine Einheit.

Endung Bedeutung
Percent 0 bis 100
S Sekunden
M Meter
Mps Meter je Sekunde
Kmh Kilometer je Stunde
W, Kw, Kwh Watt, Kilowatt, Kilowattstunden

Die Felder

Feld Einheit Vorgabe Bedeutung
hasSimulationData Flag false false, solange keine gültige Nachricht ankam. Den Zustand „keine Daten“ zeichnet der Konsument.
hasEnergyData Flag false false, wenn der Tick keine Fahrzeugmodell-Daten trägt
timeS s 0 Zeit seit Beginn der Fahrt. Ein kleinerer Wert als zuvor gilt als neue Fahrt und setzt die Akkumulatoren zurück.
distanceM m 0 absolut zurückgelegte Strecke
wheelspeedMps m/s 0 Radgeschwindigkeit, ungeglättet. Grundlage der Rechnung.
speedKmh km/h 0 geglättete Geschwindigkeit für die Anzeige
gear "P" "P", "R", "N", "D" oder eine Gangzahl
batteryEnergyKwh kWh 0 Energie in der Batterie. Aus ihrer Abnahme kommen Verbrauch und Reichweite.
batterySocPercent % 0 Ladestand der Batterie
pBatteryKw kW 0 aktuelle Batterieleistung, negativ beim Rekuperieren
pAeroW, pRollW, pUpW, pPowertrainLossW, pHydraulicW W 0 die Leistungsanteile: Luftwiderstand, Rollwiderstand, Steigung, Antriebsstrang-Verlust, hydraulische Bremse
optimalSpeedKmh km/h 0 vom Optimierer empfohlene Geschwindigkeit. 0 heißt „keine Empfehlung“.
optimalPowerW W 0 vom Optimierer empfohlene Batterieleistung
referenceSpeedLine Liste [] Referenzgeschwindigkeit aus der Offline-Optimierung. Leer heißt „keine Referenz“.
mpcSpeedLine Liste [] Geschwindigkeitsprognose des MPC über die Strecke
mpcPowerLine, mpcPowerLineTime Liste [] Leistungsprognose des MPC, über die Strecke und über die Zeit
mpcStateMachineState null Zustand der MPC-Zustandsmaschine. null zeigt nichts.
vehiclesAhead Liste [] die Fahrzeuge voraus auf der eigenen Spur, nach Abstand sortiert
speedLimitKmh km/h 0 geltendes Tempolimit. 0 heißt „unbekannt“.
nextSpeedLimitKmh km/h null Tempolimit des nächsten Schilds voraus
nextSpeedLimitDistanceM m null Abstand bis zum nächsten Tempolimit-Schild
trafficLightsAhead Liste [] Ampeln und Stoppschilder voraus, nach Abstand sortiert
stopDistanceBrakeM, stopDistanceStrongRecuperationM, stopDistanceLightRecuperationM, stopDistanceCoastingM m null die vier Haltepunkte des Kinetic Beam, je Bremsart einer

INPUT_FIELDS trägt dieselbe Tabelle im Code: Einheit, Bereich und Schrittweite je Feld. Daraus lässt sich ein Regler-Panel bauen, oder man liest sie als Beleg für einen plausiblen Wert.

Die Displays

Die Export-Namen stammen aus den Arbeitspaketen des Projekts, nicht aus der Funktion. Die Spalte „zeigt“ sagt, was zu erwarten ist.

Familie Export Zeigt
AP4 AP4ConsumptionDisplay eine bildfüllende Straße mit dem Verbrauch der letzten 150 m als Spur
AP4 AP4VelocityDisplay dieselbe Straße, mit der gefahrenen Geschwindigkeit gegen die Linie des Optimierers
AP5 AP5BaselineDisplay Geschwindigkeit, Gang, Ladestand und Verbrauch, dazu ein hoher Leistungsbalken
AP5 AP5BoxDisplay graue Kästen in den Größen der AP5-Teile: eine Layout-Vorlage, und das einzige Display ohne Eingabe
AP5 AP5ComperatorDisplay das Leistungsbalken-Feld, dazu den Energie-Score als Balken
AP5 AP5DecisionDisplay das Leistungsbalken-Feld, mit einer Marke für die empfohlene Leistung
AP5 AP5DecisionSpeedDisplay einen Geschwindigkeitsbalken mit je einer Marke für aktuelle und empfohlene Geschwindigkeit
AP5 AP5InputDisplay den Leistungsbalken geteilt in Steigung, Luftwiderstand, Rollwiderstand, Antriebsstrang-Verlust und Bremse
AP5 AP5SpeedometerDisplay Geschwindigkeit und Gang vor einem großen Bogen
AP6 AP6DefaultDisplay nur Geschwindigkeit und Gang, in der Größe ihres Inhalts
AP6 AP6StatusQuoDisplay ein Tacho-Feld mit zweiteiligem Balken, gefüllt nach dem Anteil an der Höchstleistung
AP6 AP6VariationDisplay denselben zweiteiligen Balken, gefüllt nach dem Verbrauch je Strecke
LEM LEMDisplay Leistung gegen empfohlene Leistung über 150 m zurück und voraus
LEM LEMTimeDisplay dieselbe Leistungskurve über 20 Sekunden zurück und voraus
LEM LEMVelocityTimeDisplay Geschwindigkeit über 20 Sekunden zurück und voraus, mit Prognose und Referenzlinie
LEM LEMDecisionDisplay ein AP5-Feld mit farbiger Zielgeschwindigkeit, daneben einen Leistungsbalken mit Bremsanteil
InputTransparenz InputTransparenzDisplay die Strecke voraus mit Fahrzeugen, dem nächsten Tempo-Schild und der nächsten Ampel
EnergyScore EnergyScoreBarDisplay ein kleines Feld über dem Video: Geschwindigkeit, Gang und Ladestand neben einem grünen Effizienz-Balken
EnergyScore EnergyScoreGlyphDisplay dasselbe kleine Feld, mit einem Smiley statt des Balkens
EnergyScore MinimalGaugeDisplay nur Geschwindigkeit und Gang, klein gezeichnet

Zwei Namen führen in die Irre. LEMDecisionDisplay ist ein AP5-Feld mit LEM-Namen und liest die AP5-Felder. MinimalGaugeDisplay steht in der EnergyScore-Familie, rechnet aber wie AP6.

Fahrzeugprofil

Die Displays skalieren die Eingabe gegen ein Fahrzeug. Jedes Display, dessen Rechnung davon abhängt, nimmt die optionale Prop vehicle. Ohne die Prop gilt defaultVehicleProfile mit den Werten des Simulator-Pkw.

import { AP6DefaultDisplay, defaultVehicleProfile } from "@ecosimlab/ecodisplays"

const smallCar = { ...defaultVehicleProfile, maxPowerKw: 80, batteryCapacityKwh: 22 }
Feld Einheit Was es skaliert
maxPowerKw kW den Leistungsbalken
batteryCapacityKwh kWh den Ladestand in Prozent (LEM)
rangeAtFullBatteryKm km die Reichweite, die LEM zeigt
consumptionMaxKwh, consumptionMinKwh kWh oberes und unteres Ende des Verbrauchsbalkens
defaultConsumptionKwhPer100Km kWh/100 km den Ersatzverbrauch, solange der gemessene noch 0 ist
scorePowerMaxKw kW wie stark eine Abweichung von der Empfehlung den Energie-Score senkt

Die AP4-Displays zeichnen die rohe Spur und nehmen kein Profil.

Stylesheet

Das Paket liefert sein CSS zweimal. Der Text ist in beiden Fällen derselbe.

Als Datei, wenn der Build CSS bündelt:

import "@ecosimlab/ecodisplays/styles.css"

Als String, wenn er das nicht tut — etwa bei einem Bundle aus einer Datei:

import { css, fontFaceCss } from "@ecosimlab/ecodisplays/styles"

const style = document.createElement("style")
style.textContent = css
document.head.append(style)

Wird ein Display in einem Shadow Root gezeichnet, gehört fontFaceCss zusätzlich ins Dokument. Der Browser liest @font-face nur aus dem Dokument, nie aus einem Shadow Root. Ohne diesen Schritt fallen die Displays auf eine Systemschrift zurück.

Das Stylesheet enthält keinen globalen CSS-Reset. Es lässt die Seite um sich herum unberührt. Wer einen Reset braucht, lädt ihn selbst.

Die Schrift ist Inter, unter der SIL Open Font License 1.1. Die Schriftdateien liegen als woff2 im Paket, eingebettet ins CSS als Data-URI. Zur Laufzeit lädt nichts aus dem Netz.

Entwicklung & Tests

Das Repo klonen und mit bun installieren. Die Skripte der package.json:

Befehl Wirkung
bun run dev startet das Showcase: jedes Display mit einer erfundenen Fahrt, eine Seite je Display
bun run build schreibt dist/ neu
bun run test führt die Tests mit bun test --conditions browser aus
bun run typecheck prüft Quelle und Tests mit tsc --noEmit
bun run lint prüft src/ mit Biome
bun run check baut erneut und schlägt fehl, wenn dist/ nicht zur Quelle passt oder die Version nicht zum Tag

Ein Release ist ein Commit mit neuer Version, passendem dist/ und einem Tag. Es gibt keinen Publish-Schritt und keine Registry.

Lizenz & Zitation

MIT. Die Datei LICENSE trägt den Text, AUTHORS nennt die Personen hinter dem Code, und ASSETS.md listet jedes Bild und jede Schrift mit Quelle und Lizenz. Zitiert wird die Bibliothek in Version 1.0.2, Tag v1.0.2.

Offene Punkte

  • Das README nennt in seinen Installationsbeispielen noch v0.5.0, neuester Tag ist v1.0.2. Das README ist an dieser Stelle veraltet.
  • Die Konsumenten videosimlab-cockpit-replay und videosimlab-template nageln v1.0.1 fest, einen Tag hinter der Bibliothek.
  • Die Prop kineticBeam von InputTransparenzDisplay zeichnet die vier Haltepunkte auf die Fahrbahn. Die Quelle nennt sie einen Versuch, noch keine Studienbedingung. Vorgabe ist aus.