@stocksharp/trading-controls 1.3.0 → 1.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (62) hide show
  1. package/README.md +113 -5
  2. package/dist/esm/chart-engine.js +15 -0
  3. package/dist/esm/chart-engine.js.map +1 -0
  4. package/dist/esm/control-types.js +4 -0
  5. package/dist/esm/control-types.js.map +1 -1
  6. package/dist/esm/equity-widget.js +261 -0
  7. package/dist/esm/equity-widget.js.map +1 -0
  8. package/dist/esm/heatmap-grid.js +271 -0
  9. package/dist/esm/heatmap-grid.js.map +1 -0
  10. package/dist/esm/index.js +19 -0
  11. package/dist/esm/index.js.map +1 -1
  12. package/dist/esm/optimization-heatmap-widget.js +303 -0
  13. package/dist/esm/optimization-heatmap-widget.js.map +1 -0
  14. package/dist/esm/option-smile-widget.js +252 -0
  15. package/dist/esm/option-smile-widget.js.map +1 -0
  16. package/dist/esm/pnl-curve.js +5 -1
  17. package/dist/esm/pnl-curve.js.map +1 -1
  18. package/dist/esm/surface-grid.js +282 -0
  19. package/dist/esm/surface-grid.js.map +1 -0
  20. package/dist/esm/surface-widget.js +379 -0
  21. package/dist/esm/surface-widget.js.map +1 -0
  22. package/dist/sstradingcontrols.js +1595 -168
  23. package/dist/sstradingcontrols.js.map +4 -4
  24. package/dist/types/chart-engine.d.ts +3 -0
  25. package/dist/types/chart-engine.d.ts.map +1 -0
  26. package/dist/types/control-types.d.ts +4 -0
  27. package/dist/types/control-types.d.ts.map +1 -1
  28. package/dist/types/equity-widget.d.ts +34 -0
  29. package/dist/types/equity-widget.d.ts.map +1 -0
  30. package/dist/types/heatmap-grid.d.ts +88 -0
  31. package/dist/types/heatmap-grid.d.ts.map +1 -0
  32. package/dist/types/index.d.ts +15 -0
  33. package/dist/types/index.d.ts.map +1 -1
  34. package/dist/types/optimization-heatmap-widget.d.ts +45 -0
  35. package/dist/types/optimization-heatmap-widget.d.ts.map +1 -0
  36. package/dist/types/option-smile-widget.d.ts +39 -0
  37. package/dist/types/option-smile-widget.d.ts.map +1 -0
  38. package/dist/types/pnl-curve.d.ts +3 -0
  39. package/dist/types/pnl-curve.d.ts.map +1 -1
  40. package/dist/types/surface-grid.d.ts +64 -0
  41. package/dist/types/surface-grid.d.ts.map +1 -0
  42. package/dist/types/surface-widget.d.ts +64 -0
  43. package/dist/types/surface-widget.d.ts.map +1 -0
  44. package/package.json +28 -2
  45. package/screenshots/equity.png +0 -0
  46. package/screenshots/optimization-surface.png +0 -0
  47. package/screenshots/optimization.png +0 -0
  48. package/screenshots/option-smile.png +0 -0
  49. package/screenshots/panels.jpg +0 -0
  50. package/src/chart-engine.global.ts +64 -0
  51. package/src/chart-engine.ts +29 -0
  52. package/src/control-types.ts +4 -0
  53. package/src/equity-widget.ts +289 -0
  54. package/src/heatmap-grid.ts +405 -0
  55. package/src/index.ts +46 -0
  56. package/src/optimization-heatmap-widget.ts +347 -0
  57. package/src/option-smile-widget.ts +281 -0
  58. package/src/pnl-curve.ts +13 -1
  59. package/src/surface-grid.ts +410 -0
  60. package/src/surface-widget.ts +457 -0
  61. package/styles/trading-controls.css +281 -0
  62. package/translation-keys.json +14 -1
@@ -0,0 +1 @@
1
+ {"version":3,"file":"optimization-heatmap-widget.js","sourceRoot":"","sources":["../../src/optimization-heatmap-widget.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,252 @@
1
+ // Option smile — multi-instance.
2
+ //
3
+ // One expiry's implied volatility against strike, call side and put side as two curves on one
4
+ // scale, drawn by @stocksharp/chart.
5
+ //
6
+ // The engine is a time-series engine and this axis is a ladder of strikes, which looked at first
7
+ // like a reason to draw the chart by hand. It is not: the axis carries numbers, and what turns
8
+ // them into dates is `timeScale.formatter` - one function shared by the tick labels and the
9
+ // crosshair label. Given a formatter that words a number as a strike, the axis is a strike axis,
10
+ // and the crosshair, the legend readout, the zoom and the pan come with it rather than being
11
+ // written again here.
12
+ //
13
+ // `mode: 'ordinal'` on top of that, because a listed chain is evenly spaced by listing rather
14
+ // than by the gaps between its numbers: a venue that lists 67000, 67250 and then 68000 means
15
+ // three rungs, not a hole.
16
+ import { formatPrice } from './formatters.js';
17
+ import { makeElement, makeIconButton, makePanelId, makePanelRoot } from './dom.js';
18
+ import { ControlTypes } from './control-types.js';
19
+ import { assertHost } from './trading-host.js';
20
+ import { CrosshairMode, LineSeries, createChart, } from './chart-engine.js';
21
+ const LINE_WIDTH = 2;
22
+ /// The volatility a side is drawn at: what it last traded at, or the middle of its quote when it
23
+ /// has not traded. Null when neither is known - a strike nobody has quoted is a gap in the curve,
24
+ /// and a line drawn through it invents a quote nobody made.
25
+ export function sideVolatility(side) {
26
+ if (side === undefined || side === null)
27
+ return null;
28
+ const last = side.ivLast;
29
+ if (typeof last === 'number' && isFinite(last) && last > 0)
30
+ return last;
31
+ const bid = side.ivBid;
32
+ const ask = side.ivAsk;
33
+ const quoted = [bid, ask].filter((v) => typeof v === 'number' && isFinite(v) && v > 0);
34
+ if (quoted.length === 0)
35
+ return null;
36
+ return quoted.reduce((sum, v) => sum + v, 0) / quoted.length;
37
+ }
38
+ /// The chain in the order it is drawn: by strike, lowest first, whatever order it arrived in.
39
+ export function sortedChain(strikes) {
40
+ return [...strikes]
41
+ .filter(row => row !== null && row !== undefined && isFinite(row.strike))
42
+ .sort((a, b) => a.strike - b.strike);
43
+ }
44
+ /// One side as a series, and the strikes it was drawn at.
45
+ ///
46
+ /// The x value is the strike itself rather than an index: the axis words it back through the
47
+ /// formatter, so the number on the wire and the number on the label are the same one and no
48
+ /// lookup can put them out of step.
49
+ export function toSmileSeries(chain, put) {
50
+ const out = [];
51
+ for (const row of chain) {
52
+ const volatility = sideVolatility(put ? row.put : row.call);
53
+ // Whitespace rather than a point: the engine keeps the rung on the axis and leaves the
54
+ // line broken across it, which is what a strike quoted on one side only looks like.
55
+ if (volatility === null)
56
+ out.push({ time: row.strike });
57
+ else
58
+ out.push({ time: row.strike, value: volatility * 100 });
59
+ }
60
+ return out;
61
+ }
62
+ export class OptionSmileWidget {
63
+ static create(hostEl, state, deps) {
64
+ const host = assertHost(deps?.host, 'OptionSmileWidget');
65
+ const root = OptionSmileWidget._buildRoot(host);
66
+ root.id = makePanelId(OptionSmileWidget.TYPE);
67
+ hostEl.appendChild(root);
68
+ return new OptionSmileWidget(root, state || {}, deps);
69
+ }
70
+ static _buildRoot(host) {
71
+ const title = host.t('OptionSmile');
72
+ return makePanelRoot('option-smile-panel', title, [
73
+ makeElement('div', 'panel-header', {}, [
74
+ makeElement('span', '', {}, [title]),
75
+ makeIconButton('bt-icon-btn option-smile-reset-btn', host.t('ResetView'), 'bi-arrow-clockwise', { type: 'button' }),
76
+ makeIconButton('bt-icon-btn bt-icon-cancel panel-close-btn', host.t('ClosePanel'), 'bi-x', { type: 'button' }),
77
+ ]),
78
+ makeElement('div', 'panel-body', {}, [
79
+ makeElement('div', 'option-smile-legend', {}, [
80
+ makeElement('span', 'option-smile-axis', {}, [host.t('ImpliedVolatility')]),
81
+ makeElement('span', 'option-smile-key', {}, [
82
+ makeElement('span', 'option-smile-dot option-smile-dot-call', {}, []),
83
+ host.t('Call'),
84
+ ]),
85
+ makeElement('span', 'option-smile-key', {}, [
86
+ makeElement('span', 'option-smile-dot option-smile-dot-put', {}, []),
87
+ host.t('Put'),
88
+ ]),
89
+ makeElement('span', 'option-smile-spot', {}, []),
90
+ ]),
91
+ makeElement('div', 'option-smile-chart', { role: 'img', 'aria-label': host.t('OptionChain') }, [
92
+ // Over the chart, not in the panel header: a reading about the point under the
93
+ // pointer belongs beside that point, and a host that lifts panel headers into a
94
+ // tab strip would otherwise write it into a tab title.
95
+ makeElement('div', 'option-smile-hover', {}, []),
96
+ makeElement('div', 'option-smile-empty', {}, [host.t('NoOptions')]),
97
+ ]),
98
+ ]),
99
+ ]);
100
+ }
101
+ constructor(rootEl, _state, deps) {
102
+ this._host = assertHost(deps?.host, 'OptionSmileWidget');
103
+ this.rootEl = rootEl;
104
+ this._closeBtn = this.rootEl.querySelector('.panel-close-btn');
105
+ this._resetBtn = this.rootEl.querySelector('.option-smile-reset-btn');
106
+ this._emptyEl = this.rootEl.querySelector('.option-smile-empty');
107
+ this._chartEl = this.rootEl.querySelector('.option-smile-chart');
108
+ this._spotEl = this.rootEl.querySelector('.option-smile-spot');
109
+ this._hoverEl = this.rootEl.querySelector('.option-smile-hover');
110
+ this._chart = null;
111
+ this._call = null;
112
+ this._put = null;
113
+ this._strikes = [];
114
+ this._context = {};
115
+ this._resizeObserver = null;
116
+ this._closeBtn?.addEventListener('click', (e) => { e.preventDefault(); this._host.close(); });
117
+ this._resetBtn?.addEventListener('click', (e) => { e.preventDefault(); this.resetZoom(); });
118
+ if (this._chartEl !== null && typeof ResizeObserver !== 'undefined') {
119
+ this._resizeObserver = new ResizeObserver(() => this._fit());
120
+ this._resizeObserver.observe(this._chartEl);
121
+ }
122
+ this._render();
123
+ this._host.register(this);
124
+ }
125
+ dispose() {
126
+ try {
127
+ this._resizeObserver?.disconnect();
128
+ }
129
+ catch { /* already torn down */ }
130
+ this._resizeObserver = null;
131
+ try {
132
+ this._chart?.remove();
133
+ }
134
+ catch { /* already gone */ }
135
+ this._chart = null;
136
+ this._call = null;
137
+ this._put = null;
138
+ this._host.unregister(this);
139
+ try {
140
+ this.rootEl.remove();
141
+ }
142
+ catch { /* already detached */ }
143
+ }
144
+ /// Show this chain, priced against this context.
145
+ ///
146
+ /// The desk's two arguments unchanged, and for the same reason it takes them together: they
147
+ /// are one observation. A smile marked with a spot the curves never saw is two moments.
148
+ update(strikes, context = {}) {
149
+ this._strikes = strikes || [];
150
+ this._context = context || {};
151
+ this._render();
152
+ }
153
+ /// Show the whole chain again, after a zoom.
154
+ resetZoom() {
155
+ try {
156
+ this._chart?.timeScale().fitContent();
157
+ }
158
+ catch { /* no chart yet */ }
159
+ }
160
+ /// The engine, for a host that wants to add to this chart - a second expiry, a marker.
161
+ chart() {
162
+ return this._chart;
163
+ }
164
+ _ensureChart() {
165
+ if (this._chart !== null)
166
+ return true;
167
+ if (this._chartEl === null)
168
+ return false;
169
+ const palette = this._host.presentation.canvasPalette();
170
+ this._chart = createChart(this._chartEl, {
171
+ layout: {
172
+ background: { type: 'solid', color: 'transparent' },
173
+ textColor: palette.grid,
174
+ fontFamily: palette.font,
175
+ fontSize: 11,
176
+ attributionLogo: false,
177
+ },
178
+ grid: { vertLines: { color: palette.grid }, horzLines: { color: palette.grid } },
179
+ crosshair: { mode: CrosshairMode.Normal },
180
+ rightPriceScale: { borderColor: palette.grid },
181
+ timeScale: {
182
+ borderColor: palette.grid,
183
+ // Evenly spaced by listing, and worded as strikes: the axis carries the strike
184
+ // itself, so the label and the value can never drift apart.
185
+ mode: 'ordinal',
186
+ formatter: (value) => formatPrice(Number(value)),
187
+ },
188
+ });
189
+ this._call = this._chart.addSeries(LineSeries, { lineWidth: LINE_WIDTH, color: palette.up });
190
+ this._put = this._chart.addSeries(LineSeries, { lineWidth: LINE_WIDTH, color: palette.down });
191
+ this._chart.subscribeCrosshairMove((param) => this._renderHover(param));
192
+ return true;
193
+ }
194
+ _render() {
195
+ const chain = sortedChain(this._strikes);
196
+ const quoted = chain.some(row => sideVolatility(row.call) !== null || sideVolatility(row.put) !== null);
197
+ if (this._emptyEl !== null)
198
+ this._emptyEl.hidden = quoted;
199
+ this._renderSpot();
200
+ if (!quoted)
201
+ return;
202
+ if (!this._ensureChart() || this._call === null || this._put === null)
203
+ return;
204
+ this._call.setData(toSmileSeries(chain, false));
205
+ this._put.setData(toSmileSeries(chain, true));
206
+ this._fit();
207
+ }
208
+ _fit() {
209
+ if (this._chart === null || this._chartEl === null)
210
+ return;
211
+ const rect = this._chartEl.getBoundingClientRect();
212
+ if (rect.width <= 0 || rect.height <= 0)
213
+ return;
214
+ try {
215
+ this._chart.resize(rect.width, rect.height);
216
+ }
217
+ catch { /* the engine is between frames */ }
218
+ }
219
+ // Where the money is. Not a line on the chart: an ordinal axis has a rung per listed strike
220
+ // and the spot is between two of them, so it is stated rather than drawn at a place the
221
+ // ladder does not have.
222
+ _renderSpot() {
223
+ const el = this._spotEl;
224
+ if (el === null)
225
+ return;
226
+ const spot = this._context.assetPrice;
227
+ if (typeof spot !== 'number' || !isFinite(spot)) {
228
+ el.textContent = '';
229
+ return;
230
+ }
231
+ el.textContent = `${this._host.t('Underlying')} ${formatPrice(spot)}`;
232
+ }
233
+ // What the pointer is over: the strike and both sides at it. Both, because a smile is read by
234
+ // the distance between the two curves - a readout naming one of them answers half of it.
235
+ _renderHover(param) {
236
+ const el = this._hoverEl;
237
+ if (el === null)
238
+ return;
239
+ if (param.time === null) {
240
+ el.textContent = '';
241
+ return;
242
+ }
243
+ const at = (series) => {
244
+ const point = series === null ? undefined : param.seriesData.get(series);
245
+ const value = point?.value;
246
+ return typeof value === 'number' && isFinite(value) ? `${value.toFixed(2)}%` : '--';
247
+ };
248
+ el.textContent = `${formatPrice(Number(param.time))} ${at(this._call)} / ${at(this._put)}`;
249
+ }
250
+ }
251
+ OptionSmileWidget.TYPE = ControlTypes.OptionSmile;
252
+ //# sourceMappingURL=option-smile-widget.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"option-smile-widget.js","sourceRoot":"","sources":["../../src/option-smile-widget.ts"],"names":[],"mappings":"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"}
@@ -86,6 +86,7 @@ export function pnlCurve(points, box) {
86
86
  const y = (value) => (valueSpan === 0 ? top : bottom - ((value - min) / valueSpan) * (bottom - top));
87
87
  const curve = shown.map(p => [x(p.time), y(p.value)]);
88
88
  const zeroY = y(0);
89
+ const last = shown[shown.length - 1].value;
89
90
  return {
90
91
  points: curve,
91
92
  // Closed along the baseline rather than along the foot of the box: a run entirely above
@@ -94,7 +95,10 @@ export function pnlCurve(points, box) {
94
95
  zeroY,
95
96
  min,
96
97
  max,
97
- positive: shown[shown.length - 1].value >= 0,
98
+ from: firstTime,
99
+ to: lastTime,
100
+ last,
101
+ positive: last >= 0,
98
102
  };
99
103
  }
100
104
  /// Paint a laid-out curve: the baseline, the filled area under it, then the line itself.
@@ -1 +1 @@
1
- {"version":3,"file":"pnl-curve.js","sourceRoot":"","sources":["../../src/pnl-curve.ts"],"names":[],"mappings":"AAAA,0EAA0E;AAC1E,EAAE;AACF,+FAA+F;AAC/F,8FAA8F;AAC9F,6FAA6F;AAC7F,6FAA6F;AAC7F,4FAA4F;AAiC5F,gFAAgF;AAChF,GAAG;AACH,iGAAiG;AACjG,8FAA8F;AAC9F,iGAAiG;AACjG,0FAA0F;AAC1F,eAAe;AACf,GAAG;AACH,8FAA8F;AAC9F,+FAA+F;AAC/F,8FAA8F;AAC9F,8FAA8F;AAC9F,wCAAwC;AACxC,MAAM,UAAU,WAAW,CAAC,MAA2B,EAAE,KAAa;IAClE,IAAI,MAAM,CAAC,MAAM,IAAI,KAAK,IAAI,KAAK,GAAG,CAAC;QAAE,OAAO,MAAM,CAAC,KAAK,EAAE,CAAC;IAE/D,MAAM,KAAK,GAAG,MAAM,CAAC,CAAC,CAAC,CAAC;IACxB,MAAM,IAAI,GAAG,MAAM,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;IACvC,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,GAAG,KAAK,CAAC,IAAI,CAAC;IAEpC,6FAA6F;IAC7F,IAAI,CAAC,CAAC,IAAI,GAAG,CAAC,CAAC,EAAE,CAAC;QACd,MAAM,IAAI,GAAG,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC,GAAG,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC;QAC/C,OAAO,KAAK,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,KAAK,EAAE,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC;IACjF,CAAC;IAED,4FAA4F;IAC5F,4FAA4F;IAC5F,2CAA2C;IAC3C,4FAA4F;IAC5F,0FAA0F;IAC1F,0FAA0F;IAC1F,0CAA0C;IAC1C,MAAM,OAAO,GAAG,KAAK,GAAG,CAAC,CAAC;IAC1B,MAAM,GAAG,GAAe,CAAC,KAAK,CAAC,CAAC;IAChC,IAAI,MAAM,GAAG,CAAC,CAAC;IACf,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACrC,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,OAAO,GAAG,CAAC,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,IAAI,GAAG,KAAK,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC;QAClG,IAAI,KAAK,GAAG,MAAM,EAAE,CAAC;YACjB,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;YACxB,MAAM,GAAG,KAAK,CAAC;QACnB,CAAC;IACL,CAAC;IACD,IAAI,GAAG,CAAC,GAAG,CAAC,MAAM,GAAG,CAAC,CAAC,KAAK,IAAI;QAAE,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAEjD,OAAO,GAAG,CAAC;AACf,CAAC;AAED,mEAAmE;AACnE,GAAG;AACH,8FAA8F;AAC9F,6FAA6F;AAC7F,8FAA8F;AAC9F,6FAA6F;AAC7F,MAAM,UAAU,QAAQ,CAAC,MAA2B,EAAE,GAAW;IAC7D,MAAM,KAAK,GAAG,MAAM;SACf,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,KAAK,IAAI,IAAI,CAAC,KAAK,SAAS,IAAI,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC;SACjG,KAAK,EAAE;SACP,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC;IAErC,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC;QAAE,OAAO,IAAI,CAAC;IAElC,6FAA6F;IAC7F,6FAA6F;IAC7F,4EAA4E;IAC5E,MAAM,QAAQ,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,KAAK,GAAG,GAAG,CAAC,IAAI,GAAG,CAAC,CAAC,CAAC,CAAC;IACnE,MAAM,KAAK,GAAG,WAAW,CAAC,KAAK,EAAE,QAAQ,CAAC,CAAC;IAE3C,MAAM,MAAM,GAAG,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC;IACvC,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,GAAG,MAAM,CAAC,CAAC;IACnC,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,GAAG,MAAM,CAAC,CAAC;IAEnC,MAAM,IAAI,GAAG,GAAG,CAAC,IAAI,CAAC;IACtB,MAAM,KAAK,GAAG,GAAG,CAAC,KAAK,GAAG,GAAG,CAAC,IAAI,CAAC;IACnC,MAAM,GAAG,GAAG,GAAG,CAAC,IAAI,CAAC;IACrB,MAAM,MAAM,GAAG,GAAG,CAAC,MAAM,GAAG,GAAG,CAAC,IAAI,CAAC;IAErC,MAAM,SAAS,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;IAChC,MAAM,QAAQ,GAAG,KAAK,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC;IAC9C,MAAM,QAAQ,GAAG,QAAQ,GAAG,SAAS,CAAC;IACtC,MAAM,SAAS,GAAG,GAAG,GAAG,GAAG,CAAC;IAE5B,0FAA0F;IAC1F,2FAA2F;IAC3F,oEAAoE;IACpE,MAAM,CAAC,GAAG,CAAC,IAAY,EAAU,EAAE,CAAC,CAAC,QAAQ,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,GAAG,CAAC,CAAC,IAAI,GAAG,SAAS,CAAC,GAAG,QAAQ,CAAC,GAAG,CAAC,KAAK,GAAG,IAAI,CAAC,CAAC,CAAC;IACtH,MAAM,CAAC,GAAG,CAAC,KAAa,EAAU,EAAE,CAAC,CAAC,SAAS,KAAK,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC,KAAK,GAAG,GAAG,CAAC,GAAG,SAAS,CAAC,GAAG,CAAC,MAAM,GAAG,GAAG,CAAC,CAAC,CAAC;IAErH,MAAM,KAAK,GAAG,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAqB,CAAC,CAAC;IAC1E,MAAM,KAAK,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;IAEnB,OAAO;QACH,MAAM,EAAE,KAAK;QACb,wFAAwF;QACxF,qEAAqE;QACrE,IAAI,EAAE,CAAC,GAAG,KAAK,EAAE,CAAC,KAAK,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,KAAK,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC;QAC3E,KAAK;QACL,GAAG;QACH,GAAG;QACH,QAAQ,EAAE,KAAK,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,KAAK,IAAI,CAAC;KAC/C,CAAC;AACN,CAAC;AAiCD,yFAAyF;AACzF,MAAM,UAAU,YAAY,CAAC,GAAoB,EAAE,KAAe,EAAE,GAAW,EAAE,KAAoB;IACjG,MAAM,MAAM,GAAG,KAAK,CAAC,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC;IAEtD,GAAG,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC,EAAE,GAAG,CAAC,KAAK,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;IAE3C,GAAG,CAAC,WAAW,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;IACxB,GAAG,CAAC,WAAW,GAAG,KAAK,CAAC,QAAQ,CAAC;IACjC,GAAG,CAAC,SAAS,GAAG,CAAC,CAAC;IAClB,GAAG,CAAC,SAAS,EAAE,CAAC;IAChB,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,IAAI,EAAE,KAAK,CAAC,KAAK,CAAC,CAAC;IAClC,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,GAAG,GAAG,CAAC,IAAI,EAAE,KAAK,CAAC,KAAK,CAAC,CAAC;IAC9C,GAAG,CAAC,MAAM,EAAE,CAAC;IACb,GAAG,CAAC,WAAW,CAAC,EAAE,CAAC,CAAC;IAEpB,GAAG,CAAC,WAAW,GAAG,KAAK,CAAC,WAAW,CAAC;IACpC,GAAG,CAAC,SAAS,GAAG,MAAM,CAAC;IACvB,GAAG,CAAC,SAAS,EAAE,CAAC;IAChB,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IAC/C,KAAK,MAAM,CAAC,EAAE,EAAE,EAAE,CAAC,IAAI,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC;QAAE,GAAG,CAAC,MAAM,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC;IAC/D,GAAG,CAAC,SAAS,EAAE,CAAC;IAChB,GAAG,CAAC,IAAI,EAAE,CAAC;IACX,GAAG,CAAC,WAAW,GAAG,CAAC,CAAC;IAEpB,GAAG,CAAC,WAAW,GAAG,MAAM,CAAC;IACzB,GAAG,CAAC,SAAS,GAAG,KAAK,CAAC,SAAS,CAAC;IAChC,GAAG,CAAC,SAAS,EAAE,CAAC;IAChB,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IACnD,KAAK,MAAM,CAAC,EAAE,EAAE,EAAE,CAAC,IAAI,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC;QAAE,GAAG,CAAC,MAAM,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC;IACjE,GAAG,CAAC,MAAM,EAAE,CAAC;AACjB,CAAC"}
1
+ {"version":3,"file":"pnl-curve.js","sourceRoot":"","sources":["../../src/pnl-curve.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,282 @@
1
+ // The geometry of a 3D surface over a grid, as pure functions over numbers.
2
+ //
3
+ // The same measurements the heatmap lays out flat, lifted: one metric over two discrete axes,
4
+ // with the metric as height instead of as colour. It reads the same `HeatCell[]` and folds them
5
+ // the same way, so a consumer that can draw one can draw the other from the identical input.
6
+ //
7
+ // There is no library under this. A surface is a grid of quads, a rotation is two angles, and a
8
+ // projection is six multiplications - all of it arithmetic, which is why it lives here and can be
9
+ // checked against numbers rather than against pixels. What the canvas does with the result is
10
+ // stroke and fill, nothing more.
11
+ //
12
+ // Orthographic rather than perspective. A surface is read by comparing heights across it, and
13
+ // perspective makes the far side of a ridge shorter than the near side of the same ridge - the
14
+ // one comparison the picture exists to support is the one it would distort.
15
+ import { foldCells, heatScale, tintOf } from './heatmap-grid.js';
16
+ /// The tilt the surface starts at, and the bounds a drag may take it to.
17
+ ///
18
+ /// Not zero and not a right angle: at zero every cell collapses to a line, and at a right angle
19
+ /// the surface is the flat map, which is the other control. The default sits where a ridge reads
20
+ /// as a ridge.
21
+ export const MIN_PITCH = 0.12;
22
+ export const MAX_PITCH = 1.45;
23
+ export const DEFAULT_VIEW = { yaw: -0.7, pitch: 0.62, zoom: 1 };
24
+ /// How far a drag turns the surface, in radians per CSS pixel. Slow enough that a phone's thumb
25
+ /// can land on a face, fast enough that a mouse crosses the whole rotation in one sweep.
26
+ const DRAG_TO_RADIANS = 0.008;
27
+ const MIN_ZOOM = 0.4;
28
+ const MAX_ZOOM = 4;
29
+ /// A view kept inside what can be drawn.
30
+ export function clampView(view) {
31
+ const twoPi = Math.PI * 2;
32
+ return {
33
+ // Wrapped rather than clamped: turning the surface right round is a gesture a reader
34
+ // makes on purpose, to see the far side of a ridge.
35
+ yaw: ((view.yaw % twoPi) + twoPi) % twoPi,
36
+ pitch: Math.min(MAX_PITCH, Math.max(MIN_PITCH, view.pitch)),
37
+ zoom: Math.min(MAX_ZOOM, Math.max(MIN_ZOOM, view.zoom)),
38
+ };
39
+ }
40
+ /// The view a drag of this many pixels leaves behind.
41
+ export function dragView(view, dx, dy) {
42
+ return clampView({
43
+ yaw: view.yaw + dx * DRAG_TO_RADIANS,
44
+ // Dragging down tips the surface towards a top view, which is the direction the gesture
45
+ // suggests: the far edge comes up to meet the pointer.
46
+ pitch: view.pitch + dy * DRAG_TO_RADIANS,
47
+ zoom: view.zoom,
48
+ });
49
+ }
50
+ /// The view a zoom of this factor leaves behind. A wheel notch and a pinch both arrive here.
51
+ export function zoomView(view, factor) {
52
+ return clampView({ yaw: view.yaw, pitch: view.pitch, zoom: view.zoom * factor });
53
+ }
54
+ /// Where one point of the unit cube lands on screen.
55
+ ///
56
+ /// `nx` and `ny` run -1..1 across the floor, `nz` runs 0..1 upward. Exported because the widget
57
+ /// draws the floor frame from the same projection the quads use, and two projections that drift
58
+ /// apart would put the frame under a surface that has moved.
59
+ export function project(nx, ny, nz, view, box) {
60
+ const cy = Math.cos(view.yaw);
61
+ const sy = Math.sin(view.yaw);
62
+ const rx = nx * cy - ny * sy;
63
+ const ry = nx * sy + ny * cy;
64
+ const cp = Math.cos(view.pitch);
65
+ const sp = Math.sin(view.pitch);
66
+ // The scale that fits the rotated floor at any yaw: the diagonal is what has to fit, not the
67
+ // side, or the surface would grow and shrink as it turns.
68
+ const span = Math.min(box.width, box.height) / 2;
69
+ const unit = (span * view.zoom) / Math.SQRT2;
70
+ return {
71
+ x: box.width / 2 + rx * unit,
72
+ // Screen y grows downward, so height subtracts.
73
+ y: box.height / 2 + (ry * sp - nz * cp) * unit,
74
+ // Larger is nearer the viewer.
75
+ depth: ry * cp + nz * sp,
76
+ };
77
+ }
78
+ /// Lay the surface out, or null when there is nothing to draw.
79
+ ///
80
+ /// A quad needs all four of its corners, so a pair with no run leaves a hole rather than being
81
+ /// interpolated across - the same rule the flat map draws a gap by, for the same reason: an
82
+ /// absent result is not a result of zero.
83
+ export function surfaceLayout(input) {
84
+ const buckets = foldCells(input.cells);
85
+ if (buckets.length === 0)
86
+ return null;
87
+ const xValues = axisOrder(buckets.map(b => b.x));
88
+ const yValues = axisOrder(buckets.map(b => b.y));
89
+ if (xValues.length < 2 || yValues.length < 2)
90
+ return null;
91
+ const scale = heatScale(buckets);
92
+ const at = new Map();
93
+ for (const bucket of buckets)
94
+ at.set(`${bucket.x} ${bucket.y}`, bucket);
95
+ const box = { width: input.width, height: input.height };
96
+ const view = clampView(input.view);
97
+ // Every grid point, projected once. A corner is shared by up to four quads, and projecting it
98
+ // per quad would cost four times as much and let rounding split one point into four.
99
+ const corners = [];
100
+ const vertices = [];
101
+ for (let ix = 0; ix < xValues.length; ix++) {
102
+ const column = [];
103
+ for (let iy = 0; iy < yValues.length; iy++) {
104
+ const bucket = at.get(`${xValues[ix]} ${yValues[iy]}`);
105
+ const tint = bucket === undefined ? 0 : tintOf(bucket.value, scale, input.betterWhen);
106
+ const nx = axisPosition(ix, xValues.length);
107
+ const ny = axisPosition(iy, yValues.length);
108
+ // Colour is signed around the scale's anchor and height is not: a run below the
109
+ // anchor is one the flat map paints red, but on a surface it still stands on the
110
+ // floor. So the elevation is the tint folded into 0..1, which puts the anchor half
111
+ // way up and makes the floor mean something rather than being the worst run's shelf.
112
+ const point = project(nx, ny, (tint + 1) / 2, view, box);
113
+ column.push({ ...point, tint });
114
+ // A pair nobody ran has no value to report, so it is not offered to the pointer.
115
+ if (bucket !== undefined) {
116
+ vertices.push({
117
+ at: [point.x, point.y],
118
+ x: xValues[ix],
119
+ y: yValues[iy],
120
+ value: bucket.value,
121
+ depth: point.depth,
122
+ });
123
+ }
124
+ }
125
+ corners.push(column);
126
+ }
127
+ const quads = [];
128
+ for (let ix = 0; ix + 1 < xValues.length; ix++) {
129
+ for (let iy = 0; iy + 1 < yValues.length; iy++) {
130
+ const near = at.get(`${xValues[ix]} ${yValues[iy]}`);
131
+ const holes = [
132
+ near,
133
+ at.get(`${xValues[ix + 1]} ${yValues[iy]}`),
134
+ at.get(`${xValues[ix + 1]} ${yValues[iy + 1]}`),
135
+ at.get(`${xValues[ix]} ${yValues[iy + 1]}`),
136
+ ];
137
+ if (near === undefined || holes.some(b => b === undefined))
138
+ continue;
139
+ const a = corners[ix][iy];
140
+ const b = corners[ix + 1][iy];
141
+ const c = corners[ix + 1][iy + 1];
142
+ const d = corners[ix][iy + 1];
143
+ quads.push({
144
+ points: [[a.x, a.y], [b.x, b.y], [c.x, c.y], [d.x, d.y]],
145
+ // The mean of the corners, so a face slopes in colour the way it slopes in height
146
+ // rather than taking the tint of whichever corner happened to be first.
147
+ tint: (a.tint + b.tint + c.tint + d.tint) / 4,
148
+ depth: (a.depth + b.depth + c.depth + d.depth) / 4,
149
+ bucket: near,
150
+ });
151
+ }
152
+ }
153
+ // Painter's algorithm: far first, so a near ridge covers what is behind it. Quads on a grid
154
+ // never interpenetrate, so sorting by mean depth is exact here rather than an approximation.
155
+ quads.sort((p, q) => p.depth - q.depth);
156
+ const floor = (nx, ny) => {
157
+ const p = project(nx, ny, 0, view, box);
158
+ return [p.x, p.y];
159
+ };
160
+ // Which way is out. An edge's ticks are pushed away from the floor's middle, so they stay
161
+ // outside the surface however far it has been turned - the direction is the turned edge's own
162
+ // rather than a fixed screen offset that would swing onto the landscape at some angles.
163
+ const outward = (from, to) => {
164
+ const centre = floor(0, 0);
165
+ const midX = (from[0] + to[0]) / 2;
166
+ const midY = (from[1] + to[1]) / 2;
167
+ const dx = midX - centre[0];
168
+ const dy = midY - centre[1];
169
+ const length = Math.hypot(dx, dy) || 1;
170
+ return [dx / length, dy / length];
171
+ };
172
+ // A square floor has two edges per axis, and the surface stands between them. Labels go on
173
+ // whichever is nearer the viewer: the far one is behind the landscape, where a number is drawn
174
+ // over the mesh it is supposed to be measuring. Which is nearer changes as the view turns, so
175
+ // it is decided per render rather than fixed.
176
+ const depthAt = (nx, ny) => project(nx, ny, 0, view, box).depth;
177
+ const xSide = depthAt(0, -1) >= depthAt(0, 1) ? -1 : 1;
178
+ const ySide = depthAt(-1, 0) >= depthAt(1, 0) ? -1 : 1;
179
+ const xEdge = [floor(-1, xSide), floor(1, xSide)];
180
+ const yEdge = [floor(ySide, -1), floor(ySide, 1)];
181
+ const xAway = outward(xEdge[0], xEdge[1]);
182
+ const yAway = outward(yEdge[0], yEdge[1]);
183
+ // The vertical edge rises from the corner OPPOSITE the two labelled ones. The corner they meet
184
+ // at is the nearest point of the floor, and the landscape stands directly over it - an axis
185
+ // there is drawn through the middle of the picture with its numbers over the mesh. The far
186
+ // corner is behind the surface, where a scale belongs.
187
+ const zBottom = project(-ySide, -xSide, 0, view, box);
188
+ const zTop = project(-ySide, -xSide, 1, view, box);
189
+ const zAway = outward([zBottom.x, zBottom.y], [zTop.x, zTop.y]);
190
+ return {
191
+ quads,
192
+ vertices,
193
+ axes: [
194
+ {
195
+ from: xEdge[0],
196
+ to: xEdge[1],
197
+ axis: 'x',
198
+ ticks: axisTicks(xValues, i => floor(axisPosition(i, xValues.length), xSide), xAway),
199
+ },
200
+ {
201
+ from: yEdge[0],
202
+ to: yEdge[1],
203
+ axis: 'y',
204
+ ticks: axisTicks(yValues, i => floor(ySide, axisPosition(i, yValues.length)), yAway),
205
+ },
206
+ {
207
+ from: [zBottom.x, zBottom.y],
208
+ to: [zTop.x, zTop.y],
209
+ axis: 'z',
210
+ // Five marks up the height, which is what the colour scale runs over: the floor is
211
+ // the worst run and the top the best. Worded by the caller, which knows the metric.
212
+ ticks: heightTicks(view, box, zAway, -ySide, -xSide),
213
+ },
214
+ ],
215
+ xValues,
216
+ yValues,
217
+ scale,
218
+ };
219
+ }
220
+ /// The height a tick sits at, 0..1, for each mark on the vertical axis. Exported so a caller can
221
+ /// word them: the layout knows where they land, not what the metric is called.
222
+ export const SURFACE_HEIGHT_TICKS = [0, 0.25, 0.5, 0.75, 1];
223
+ /// At most this many marks on a parameter axis. A sweep of forty settings would otherwise write
224
+ /// forty labels into the width of a chart and leave a smear.
225
+ const MAX_AXIS_TICKS = 8;
226
+ function axisTicks(values, at, away) {
227
+ if (values.length === 0)
228
+ return [];
229
+ // Every value while they fit, then every second, every third... so the first and the last are
230
+ // always marked and the spacing stays even between them.
231
+ const step = Math.max(1, Math.ceil(values.length / MAX_AXIS_TICKS));
232
+ const ticks = [];
233
+ for (let i = 0; i < values.length; i += step)
234
+ ticks.push({ at: at(i), label: values[i], away });
235
+ const last = values.length - 1;
236
+ if (last > 0 && (last % step) !== 0)
237
+ ticks.push({ at: at(last), label: values[last], away });
238
+ return ticks;
239
+ }
240
+ function heightTicks(view, box, away, nx, ny) {
241
+ return SURFACE_HEIGHT_TICKS.map(height => {
242
+ const point = project(nx, ny, height, view, box);
243
+ // The height itself as the label, for a caller that does not replace it. A caller that
244
+ // knows the metric words it as money or as a ratio.
245
+ return { at: [point.x, point.y], label: String(height), away };
246
+ });
247
+ }
248
+ /// The measured point nearest a screen position, or null when none is within `reach` pixels.
249
+ ///
250
+ /// Ties break towards the viewer: two vertices over the same pixel are a near ridge in front of a
251
+ /// far one, and the near one is what a reader is pointing at.
252
+ export function nearestVertex(vertices, x, y, reach) {
253
+ let best = null;
254
+ let bestDistance = reach;
255
+ for (const vertex of vertices) {
256
+ const distance = Math.hypot(vertex.at[0] - x, vertex.at[1] - y);
257
+ if (distance > bestDistance)
258
+ continue;
259
+ if (distance === bestDistance && best !== null && vertex.depth <= best.depth)
260
+ continue;
261
+ best = vertex;
262
+ bestDistance = distance;
263
+ }
264
+ return best;
265
+ }
266
+ /// The distinct values of one axis, in the order the grid steps through them.
267
+ ///
268
+ /// Numbers sort as numbers and everything else as text: a sweep of 5, 8, 12, 40 is a sequence,
269
+ /// and sorting it as text would put 12 before 5 and make the surface a lie about which way the
270
+ /// parameter runs.
271
+ function axisOrder(values) {
272
+ const distinct = [...new Set(values)];
273
+ const numeric = distinct.every(v => v.trim() !== '' && isFinite(Number(v)));
274
+ return numeric
275
+ ? distinct.sort((a, b) => Number(a) - Number(b))
276
+ : distinct.sort((a, b) => a.localeCompare(b));
277
+ }
278
+ /// Where the nth of `count` steps sits across the floor, -1..1.
279
+ function axisPosition(index, count) {
280
+ return count < 2 ? 0 : (index / (count - 1)) * 2 - 1;
281
+ }
282
+ //# sourceMappingURL=surface-grid.js.map