

Dieser Walkthrough baut ein echtes Diagramm von Grund auf: Installation, Daten, Achsen, Interaktion, eine laufende Echtzeit-Kurve und einen Ereignishandler für Klicks auf die Daten. Er dauert etwa zehn Minuten, und eine Build-Toolchain ist nicht erforderlich, wenn Sie keine möchten.
Wenn Sie ProEssentials auf dem Desktop bereits kennen, können Sie überfliegen. Die JavaScript-Eigenschaftsnamen sind die WinForms-Eigenschaftsnamen, und die Ereignisnamen ebenso. Schritt 10 stellt C# und JavaScript nebeneinander, damit Sie sehen, wie wenig sich ändert.
Lieber fertigen Code lesen? Öffnen Sie den Live-Beispielbrowser — jedes Beispiel zeigt seinen eigenen Quellcode neben dem Diagramm.
Zwei Wege hinein, und die Seite, die Sie schreiben, ist in beiden Fällen identisch. Nur die Pfade unterscheiden sich.
Das Starter-Repository klonen — der kürzeste Weg zu einem Diagramm auf dem Bildschirm. Die Bibliothek liegt neben der Seite im Repository, es gibt also nichts aufzulösen und nichts zu installieren:
git clone https://github.com/GigasoftInc/proessentials-js-starter
npm start
Das ist die gesamte Prozedur. Das Paket hat keine Abhängigkeiten — das eine Skript, das es definiert, startet einen kleinen statischen Server, aus dem unten genannten Grund.
Oder aus npm, in einem eigenen Projekt:
npm install proessentials
So oder so besteht die Seite aus zwei Skript-Tags. Das erste ist die Engine, ein klassisches Skript. Das zweite ist Ihr eigener Code, als Modul.
<script src="proessentials.iife.js"></script>
<script type="module" src="app.js"></script>
In app.js importieren Sie die Eigenschaftsschnittstelle für das gewünschte Diagramm. Das ist ein Import in Ihrem eigenen JavaScript, kein weiterer Include:
import { attachApi, Enums as E } from './pe-api-graph.js';
Ein einzelnes Tag ist nicht möglich, und das ist kein Mangel der Paketierung: Die Eigenschaftsschnittstellen sind echte ES-Module, und ein klassisches Skript kann keines aufnehmen. Charting-Bibliotheken, die beide Formen ausliefern, teilen an derselben Stelle. Aus npm installiert zeigen die beiden Pfade stattdessen in node_modules/proessentials/dist/ — behalten Sie das führende ./, denn ein führendes / ist eine gültige URL, die einwandfrei läuft, während Ihr Editor stillschweigend jede Vervollständigung verliert.
Sonst wird nichts konfiguriert. Kein Bundler, keine Import-Map, keine jsconfig.json, kein Kopieren von Assets. Die Bibliothek löst ihre eigene WebAssembly-Binärdatei und ihre eigenen eingebauten Bitmaps gegen ihre eigene Skript-URL auf statt gegen die Seite, sie werden also gefunden, wo immer die Bibliothek liegt. Die Editor-Vervollständigung funktioniert aus demselben Grund: Die TypeScript-Definitionen liegen neben den Modulen, die sie beschreiben.
Liefern Sie die Seite über einen Server aus. Öffnen Sie sie nicht von der Festplatte. Eine file://-URL hat keinen Origin, und ein Browser lädt ohne Origin kein WebAssembly-Modul — die Seite bleibt also leer, und nichts an ihr ist fehlerhaft. Jeder statische Server genügt, und npm start oben ist einer. Das trifft Leute, die von Bibliotheken kommen, die sich von der Festplatte öffnen lassen: Ein einfaches Skript ohne Module und ohne etwas zu laden öffnet sich problemlos. Dieses hier muss eine 2,9 MB große Engine laden, und es sagt Ihnen das, wenn Sie es versuchen.
Für all dies ist kein Lizenzschlüssel erforderlich. Es gibt keine Aktivierung, keine Domain-Registrierung und kein Phone-Home.
Ein Element. Das Diagramm passt sich seiner Größe an.
<div id="chart" style="width:800px; height:520px"></div>
Die Engine ist WebAssembly, sie lädt also einmal und asynchron. Alles danach ist synchrones Setzen von Eigenschaften.
// 1. The engine. Once per page, however many charts you go on to make //
const m = await ProEssentials();
// 2. The control. This is the WinForms designer step: dropping a Pego
// on the form. autoResize is the web Dock = Fill //
const ctl = new PeControl(document.getElementById('chart'), {
module: m,
kind: 'graph',
autoResize: true,
});
// 3. The property tree //
const Pego1 = ctl.attach(attachApi);
Drei Objekte, und jedes hat seine Aufgabe. m ist die Engine, die Sie nicht wieder anfassen werden. ctl ist das Control — ihm gehören die Canvas, das Menü, die Bildlaufleisten und die Ereignisse. Pego1 ist die Eigenschaftsschnittstelle, und dort spielt sich der Rest dieses Walkthroughs ab.
Warum Pego1? Weil das Objekt in jedem ProEssentials-Beispiel so heißt, auf jeder Plattform, seit dreißig Jahren. Nennen Sie es, wie Sie möchten — behalten Sie den Namen aber bei, lassen sich unsere Beispiele und unser KI-Assistent direkt in Ihr Projekt einfügen.
Das ist der eine Schritt, den man zweimal lesen sollte. ProEssentials erwartet die Eigenschaften in einer bestimmten Reihenfolge:
Subsets, dann Points, dann die Daten, dann alles Übrige, und render() zuletzt.
Der Grund: Jeder Datenschreibzugriff wird gegen Subsets × Points geprüft. Setzen Sie die Daten, bevor Sie dem Diagramm seine Größe genannt haben, werden die Schreibzugriffe abgewiesen — und das Diagramm zeichnet trotzdem, mit Standarddaten, und sieht dabei völlig überzeugend aus. Das ist der mit Abstand häufigste Fehler, auf jeder Plattform, und er ist leicht zu vermeiden, sobald man ihn kennt.
// 1. Shape first. Subsets = rows, Points = columns //
Pego1.PeData.Subsets = 2;
Pego1.PeData.Points = 6;
// 2. Then the data //
Pego1.PeData.Y[0][0] = 10; Pego1.PeData.Y[0][1] = 30;
Pego1.PeData.Y[0][2] = 20; Pego1.PeData.Y[0][3] = 40;
Pego1.PeData.Y[0][4] = 30; Pego1.PeData.Y[0][5] = 50;
Pego1.PeData.Y[1][0] = 15; Pego1.PeData.Y[1][1] = 63;
Pego1.PeData.Y[1][2] = 74; Pego1.PeData.Y[1][3] = 54;
Pego1.PeData.Y[1][4] = 25; Pego1.PeData.Y[1][5] = 34;
Beachten Sie die Indizierung. C# schreibt PeData.Y[s, p]; JavaScript hat keinen zweidimensionalen Indexer, also heißt es PeData.Y[s][p]. Das ist der einzige Formunterschied in der gesamten API.
Pego1.PeString.MainTitle = "Units Sold per Month";
Pego1.PeString.SubTitle = "";
Pego1.PeString.YAxisLabel = "Units Sold";
Pego1.PeString.PointLabels[0] = "Jan";
Pego1.PeString.PointLabels[1] = "Feb";
Pego1.PeString.PointLabels[2] = "Mar";
Pego1.PeString.PointLabels[3] = "Apr";
Pego1.PeString.PointLabels[4] = "May";
Pego1.PeString.PointLabels[5] = "Jun";
Pego1.PeString.SubsetLabels[0] = "Texas";
Pego1.PeString.SubsetLabels[1] = "Florida";
Die Achsenskalierung ist standardmäßig automatisch. Wenn Sie sie festsetzen müssen — und bei einem Echtzeitdiagramm fast immer, weil eine automatisch skalierende Achse sich in jedem Frame neu einpasst und die Kurve dadurch zu atmen scheint — übernehmen Sie die manuelle Kontrolle:
Pego1.PeGrid.Configure.ManualScaleControlY = E.ManualScaleControl.MinMax;
Pego1.PeGrid.Configure.ManualMinY = 0;
Pego1.PeGrid.Configure.ManualMaxY = 100;
Ein Graph-Objekt skaliert nur die Y-Achse. Es zeichnet seine Punkte gleichmäßig verteilt von links nach rechts, es gibt also keine X-Skala zum Festsetzen und kein ManualMinX. Wenn Ihre X-Werte eine eigene Bedeutung tragen, etwa Zeitstempel oder unregelmäßige Abtastintervalle, dann ist das ein Scientific Graph, der den vollständigen X-Satz unter denselben Namen besitzt. Es ist durchgehend dieselbe API; im Beispielbrowser finden Sie beides.
Die Aufzählungen liegen auf E und tragen dieselben Namen wie die .NET-Enums.
Pego1.PePlot.Method = E.GraphPlottingMethod.Bar;
Pego1.PeGrid.LineControl = E.GridLineControl.Both;
Pego1.PeGrid.Style = E.GridStyle.Dot;
Pego1.PePlot.Option.BarGlassEffect = true;
Pego1.PePlot.DataShadows = E.DataShadows.Shadows;
Zoomen, Bildlaufleisten, das Kontextmenü und der Verfolgungscursor sind alle eingebaut. Es sind Eigenschaften, kein Code, den Sie schreiben.
// Left-drag draws a zoom box; z or the popup menu undoes it //
Pego1.PeUserInterface.Allow.Zooming = E.AllowZooming.HorzAndVert;
// Follows the data under the pointer and shows the value //
Pego1.PeUserInterface.Cursor.PromptTracking = true;
// Middle-button drag to pan //
Pego1.PeUserInterface.Scrollbar.MouseDraggingX = true;
Pego1.PeUserInterface.Scrollbar.MouseDraggingY = true;
// This enables data hot spots. Step 9 writes the handler //
Pego1.PeUserInterface.HotSpot.Data = true;
Ein Aufruf, am Ende, nachdem jede Eigenschaft gesetzt ist.
ctl.render(); // last, always //
Für Echtzeit gibt es zwei Formen, und es lohnt sich zu wissen, welche Sie brauchen.
Anhängen — neue Messwerte an eine wachsende Kurve anfügen. Günstig, und die übliche Wahl für einen Streifenschreiber.
Ersetzen — dem Diagramm in jedem Frame einen völlig neuen Datensatz übergeben. Genau das tut ein Oszilloskop bei jedem Durchlauf, und jede Anwendung, deren Daten vor dem Zeichnen gefiltert oder neu berechnet werden. Das ist der schwierigere Fall, und es ist der, für den die Engine gebaut wurde: Das Beispiel unten ersetzt vier Subsets mit je 100.000 Punkten — 400.000 insgesamt — in jedem einzelnen Frame.
// requestAnimationFrame, not setInterval -- ask for what the display
// will take and never more, or the callbacks queue up //
const tick = () => {
Pego1.PeData.Y.load(block, 4, 100000); // values, subsets, points //
ctl.render();
requestAnimationFrame(tick);
};
requestAnimationFrame(tick);
Zwei Gewohnheiten, die sich lohnen. Setzen Sie die Achse fest, statt sie automatisch skalieren zu lassen, sonst passt sich das Diagramm in jedem Frame neu ein und die Kurve scheint zu atmen. Und übergeben Sie der Engine mit load() ein ganzes typisiertes Array, statt Punkt für Punkt zuzuweisen — ein Aufruf überquert die Grenze einmal.
Bei einem Scientific Graph, wo die X-Reihe echt ist, gibt es eine dritte: PeData.ReuseDataX = true, wenn sich nur Y ändert, damit die Engine keine X-Reihe neu aufbaut, die sich nicht bewegt hat. Ein Graph-Objekt hat keine X-Reihe, hier gilt das also nicht.
Schritt 7 hat die Daten-Hot-Spots aktiviert. Dies ist der Handler.
ctl.PeDataHotSpot.add((sender, ev) => {
alert("Subset " + ev.subset + ", Point " + ev.point +
" with a value of " + Pego1.PeData.Y[ev.subset][ev.point]);
});
Klicken Sie auf einen Balken. Die Engine führt beim Mausklick einen Treffertest durch, füllt den Hot-Spot-Datensatz und löst das passende Ereignis aus, mit ev.subset und ev.point bereits dekodiert. Sie hängen keinen Klick-Listener an und dekodieren keinen Typcode.
.add ist das += aus C#, und .remove ist -=. JavaScript hat keinen Operator zum Überladen, also sind die Ereignisse Methoden. Sie sind multicast, wie die .NET-Originale: Ein zweites .add fügt einen zweiten Handler hinzu, statt den ersten zu ersetzen. Jedes Handle trägt außerdem .count und .clear().
Ein Graph trägt 37 Ereignisse, geschrieben wie .NET sie schreibt — PeSubsetHotSpot, PeGraphHotSpot, PeMainTitle, PeZoomIn, PeCursorMoved und die übrigen. Ereignisse, die ein bestimmtes Control nicht auslösen kann, fehlen, statt tot zu sein: Es gibt kein Handle zum Abonnieren, ein Abonnement, das niemals feuern könnte, ist also ein TypeError in der Zeile, die es geschrieben hat, statt Stille zur Laufzeit.
Beachten Sie den Empfänger. Eigenschaften liegen auf Pego1, Ereignisse auf ctl, dem Control selbst. In WinForms liegen beide auf pego1. Im Web bleiben die Ereignisse am Control, damit auch eine Seite sie erhält, die die Eigenschaftsschnittstelle nie bindet — ein Diagramm, auf das Sie nur klicken, braucht überhaupt kein attach().
Dasselbe Diagramm, zweimal. Das ist das ganze Argument für diese API, und es lässt sich leichter zeigen als erklären.
C# — WinForms, WPF oder WinUI:
pego1.PeData.Subsets = 2;
pego1.PeData.Points = 6;
pego1.PeData.Y[0, 0] = 10;
pego1.PeString.MainTitle = "Units Sold per Month";
pego1.PePlot.Method = GraphPlottingMethod.Bar;
pego1.PeUserInterface.HotSpot.Data = true;
pego1.PeDataHotSpot += OnDataHotSpot;
pego1.PeFunction.ReinitializeResetImage();
JavaScript — der Browser:
Pego1.PeData.Subsets = 2;
Pego1.PeData.Points = 6;
Pego1.PeData.Y[0][0] = 10;
Pego1.PeString.MainTitle = "Units Sold per Month";
Pego1.PePlot.Method = E.GraphPlottingMethod.Bar;
Pego1.PeUserInterface.HotSpot.Data = true;
ctl.PeDataHotSpot.add(onDataHotSpot);
ctl.render();
Dieselben Eigenschaftsnamen, dieselbe Reihenfolge, dieselbe Engine darunter. Fünf Unterschiede, und das ist die vollständige Liste: der zweidimensionale Indexer, das Enum-Präfix, .add für +=, der Empfänger für Ereignisse und der abschließende Aufruf. Alles, was Sie über ProEssentials wissen, überträgt sich, und alles, was unser KI-Assistent weiß, ebenfalls — denn er antwortet aus demselben Eigenschaftsmodell.
Sie übertragen bestehenden Desktop-Code? Die letzte Zeile läuft wortwörtlich: Pego1.PeFunction.ReinitializeResetImage() gibt es auch auf dem JavaScript-Control, zusammen mit Reinitialize, Reset, GetRectGraph und dem Rest von PeFunction. Es ist derselbe Aufruf wie render(), die kürzere Schreibweise, die wir in neuem Browser-Code verwenden.