ProEssentialsJS v11 チュートリアル

npm インストールからリアルタイムで動く対話的なチャートまで - 実際に作る順序で、一歩ずつ

JavaScript chart walkthrough
WebAssembly chart tutorial
npm install javascript chart
javascript chart example code
ProEssentialsJS chart
javascript real time chart tutorial
canvas2d chart getting started
javascript charting library walkthrough

ProEssentialsJS v11 Walkthrough
Your first chart, step by step

このウォークスルーでは、実際に動くチャートをゼロから作ります。インストール、データ、軸、操作、リアルタイムで動くトレース、そしてデータのクリックを受け取るイベントハンドラーまで。所要時間はおよそ 10 分で、望まないのであればビルド ツールチェーンは必要ありません。

デスクトップの ProEssentials をすでにご存じなら、流し読みで構いません。 JavaScript のプロパティ名は WinForms のプロパティ名そのままで、イベント名も同じです。ステップ 10 では C# と JavaScript を並べて示し、変わる部分がいかに少ないかをご確認いただけます。

完成したコードを読むほうがよければ、ライブのサンプルブラウザを開いてください — 各サンプルはチャートの横に自身のソースを表示します。

1) インストール

入り口は 2 つあり、書くページはどちらでも同じです。違うのはパスだけです。

スターター リポジトリをクローンする — 画面にチャートを出すまでの最短経路です。ライブラリはページの隣にコミットされているので、解決するものも、インストールするものもありません。

git clone https://github.com/GigasoftInc/proessentials-js-starter
npm start

手順はこれだけです。このパッケージには依存関係がなく、定義されている 1 つのスクリプトが小さな静的サーバーを起動します。理由は下に書いたとおりです。

あるいは npm から、ご自身のプロジェクトで:

npm install proessentials

どちらの場合も、ページはスクリプトタグ 2 つです。 1 つ目がエンジンで、クラシック スクリプトです。2 つ目がご自身のコードで、モジュールとして読み込みます。

<script src="proessentials.iife.js"></script>
<script type="module" src="app.js"></script>

app.js の中で、使いたいチャートのプロパティ サーフェスを import します。これはご自身の JavaScript の中の import であって、もう 1 つの include ではありません。

import { attachApi, Enums as E } from './pe-api-graph.js';

1 つのタグにはできませんが、これはパッケージングの不備ではありません。プロパティ サーフェスは本物の ES モジュールであり、クラシック スクリプトはモジュールを収められないからです。両方の形式を提供するチャート ライブラリも、同じ線で分かれます。npm からインストールした場合、2 つのパスは代わりに node_modules/proessentials/dist/ を指します — 先頭の ./ は必ず残してください。先頭の / も URL としては正しく、ブラウザーでは問題なく動作しますが、エディターの補完だけが静かに失われます。

それ以外に設定するものはありません。 バンドラーも、import map も、jsconfig.json も、アセットのコピーも不要です。ライブラリは自身の WebAssembly バイナリと組み込みビットマップを、ページではなく自身のスクリプト URL を基準に解決するため、ライブラリがどこにあっても見つかります。エディターの補完が効くのも同じ理由で、TypeScript の型定義が、対応するモジュールの隣に置かれているからです。

ページはサーバー経由で配信してください。ディスクから直接開かないでください。 file:// の URL にはオリジンがなく、ブラウザーはオリジンのないページのために WebAssembly モジュールを取得しません — ページは白いままになりますが、ページ自体に問題はありません。静的サーバーであれば何でもよく、上の npm start もその 1 つです。ディスクから開けるライブラリから来た方がここでつまずきます。モジュールも取得するものもない素のスクリプトなら問題なく開くからです。こちらは 2.9 MB のエンジンを取得する必要があり、試せばその旨が表示されます。

以上のいずれにもライセンス キーは必要ありません。 アクティベーションも、ドメイン登録も、外部への通信もありません。

2) 描画する場所を与える

要素は 1 つです。チャートはその大きさに合わせて自身を調整します。

<div id="chart" style="width:800px; height:520px"></div>

3) チャートを生成する

エンジンは WebAssembly なので、読み込みは一度だけ、非同期で行われます。それ以降はすべて同期的なプロパティ設定です。

// 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);

3 つのオブジェクトがあり、それぞれに役割があります。 m はエンジンで、以後触れることはありません。ctl はコントロールで、キャンバス、メニュー、スクロールバー、イベントを所有します。Pego1 はプロパティ サーフェスで、このウォークスルーの残りはすべてここで行われます。

なぜ Pego1 なのか。 あらゆるプラットフォームの、あらゆる ProEssentials のサンプルで、30 年前からこのオブジェクトはそう呼ばれてきたからです。お好きな名前で構いませんが、この名前のままにしておけば、当社のサンプルも AI アシスタントの出力も、そのままプロジェクトに貼り付けられます。

4) データを渡す — そして順序に注意する

ここは二度読む価値のある唯一のステップです。 ProEssentials はプロパティを決まった順序で受け取ります。

Subsets、次に Points、次にデータ、次にそれ以外すべて、そして最後に render()

理由は、データへの書き込みがすべて Subsets × Points に対して境界チェックされるからです。チャートに大きさを伝える前にデータを設定すると、書き込みは拒否されます — それでもチャートは既定のデータで描画され、まったく問題なさそうに見えます。これはどのプラットフォームでも最も多い間違いであり、知ってさえいれば簡単に避けられます。

// 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;

添字の書き方にご注意ください。 C# では PeData.Y[s, p] と書きますが、JavaScript には 2 次元の添字がないので PeData.Y[s][p] となります。API 全体を通じて、形が異なるのはここだけです。

5) タイトル、ラベル、軸

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";

軸のスケーリングは既定で自動です。固定する必要があるとき — リアルタイム チャートではほぼ必ずそうなります。自動スケーリングの軸はフレームごとに再調整され、トレースが呼吸しているように見えてしまうからです — 手動制御に切り替えます。

Pego1.PeGrid.Configure.ManualScaleControlY = E.ManualScaleControl.MinMax;
Pego1.PeGrid.Configure.ManualMinY = 0;
Pego1.PeGrid.Configure.ManualMaxY = 100;

Graph オブジェクトがスケーリングするのは Y 軸だけです。 点は左から右へ等間隔に配置されるため、固定すべき X スケールはなく、ManualMinX もありません。X の値自体に意味がある場合、たとえばタイムスタンプや不規則なサンプリング間隔であれば、それは Scientific Graph であり、同じ名前で X 側の一式が揃っています。API は終始同じです。両方ともサンプルブラウザでご覧いただけます。

6) 描画方法を選ぶ

列挙値は E の下にあり、.NET の列挙型と同じ名前を持ちます。

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;

7) 操作できるようにする

ズーム、スクロールバー、右クリック メニュー、追従カーソルは、いずれも組み込みです。書くコードではなく、プロパティです。

// 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;

8) 描画する — そして動かし続ける

呼び出しは 1 回、すべてのプロパティを設定したあと、最後に行います。

ctl.render(); // last, always //

リアルタイムには 2 つの形があり、どちらが必要かを知っておく価値があります。

追加 — 伸びていくトレースに新しいサンプルを足していきます。負荷が軽く、ストリップ チャートでは通常こちらを選びます。

置換 — フレームごとにまったく新しいデータセットをチャートに渡します。オシロスコープが掃引のたびに行っていることであり、描画前にデータをフィルタリングまたは再計算するアプリケーションが行っていることでもあります。こちらが難しいケースであり、エンジンがそのために作られたケースでもあります。下のサンプルは、100,000 点の Subset 4 つ — 合計 400,000 点 — を毎フレーム置き換えています。

// 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);

身につける価値のある習慣が 2 つあります。 軸は自動スケーリングに任せず固定してください。さもないとチャートはフレームごとに再調整され、トレースが呼吸して見えます。そして 1 点ずつ代入するのではなく、load() で型付き配列をまるごとエンジンに渡してください — 境界を越えるのが 1 回で済みます。

X 系列が実在する Scientific Graph には 3 つ目があります。Y だけが変化する場合に PeData.ReuseDataX = true とすると、動いていない X 系列をエンジンが作り直さなくなります。Graph オブジェクトには X 系列がないため、ここでは該当しません。

9) データ点のクリックに応答する

ステップ 7 でデータのホットスポットを有効にしました。こちらがそのハンドラーです。

ctl.PeDataHotSpot.add((sender, ev) => {
  alert("Subset " + ev.subset + ", Point " + ev.point +
      " with a value of " + Pego1.PeData.Y[ev.subset][ev.point]);
});

バーをクリックしてみてください。エンジンはマウス ダウン時にヒットテストを行い、ホットスポット レコードを埋め、対応するイベントを発生させます。ev.subsetev.point はすでにデコード済みです。クリック リスナーを取り付ける必要も、型コードをデコードする必要もありません。

.add は C# の += であり、.remove-= です。 JavaScript にはオーバーロードできる演算子がないため、イベントはメソッドになっています。.NET の元のイベントと同じくマルチキャストで、2 回目の .add は 1 つ目を置き換えるのではなく、2 つ目のハンドラーを追加します。各ハンドルは .count.clear() も備えています。

Graph は 37 個のイベントを持ち、.NET と同じ綴りです — PeSubsetHotSpotPeGraphHotSpotPeMainTitlePeZoomInPeCursorMoved ほか。あるコントロールが発生させられないイベントは、死んだ状態で存在するのではなく、そもそもありません。購読する先のハンドルが存在しないので、決して発火しない購読は実行時の沈黙ではなく、それを書いた行での TypeError になります。

受け手にご注意ください。 プロパティは Pego1 に、イベントはコントロールそのものである ctl にあります。WinForms ではどちらも pego1 にあります。Web ではイベントをコントロール側に置いているため、プロパティ サーフェスを一度もバインドしないページでもイベントを受け取れます — クリックするだけのチャートなら attach() はまったく必要ありません。

10) デスクトップのコントロールをすでにご存じの場合

同じチャートを 2 通りで。これがこの API の主張のすべてであり、説明するより見せるほうが早いところです。

C# — WinForms、WPF、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 — ブラウザー:

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();

同じプロパティ名、同じ順序、同じエンジン。違いは 5 つで、それがすべてです。2 次元の添字、列挙型の接頭辞、+= に代わる .add、イベントの受け手、そして最後の呼び出し。ProEssentials についてご存じのことはすべてそのまま活かせます。当社の AI アシスタントが知っていることも同様です — 同じプロパティ モデルから答えているからです。

既存のデスクトップ コードを移植中ですか。 最後の行はそのまま動きます。Pego1.PeFunction.ReinitializeResetImage() は JavaScript のコントロールにもあり、ReinitializeResetGetRectGraph ほか PeFunction の残りも同様です。これは render() と同じ呼び出しで、新しいブラウザー向けコードでは短いほうの綴りを使っています。

次に読むもの
  • ライブのサンプルブラウザ — デスクトップ デモと同じサンプル群を、それぞれソース付きで。
  • PE-Query — 必要なプロパティを尋ねると、ドキュメントを検索した結果ではなく、コンパイル済みエンジンに対して検証された答えが返ります。
  • API エクスプローラー — すべてのコントロールの、すべてのプロパティ。
  • 他製品との比較 — Highcharts、SciChart.js、LightningChart JS ほかとの比較。
  • お問い合わせ — サポートは無料・無制限で、エンジンを書いた本人が回答します。