@tradecanvas/core 1.25.0 → 1.26.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.
- package/dist/{WebGLSeriesRenderer-C9lMIDnL.js → WebGLSeriesRenderer-BXFfVudh.js} +3 -3
- package/dist/{WebGLSeriesRenderer-C9lMIDnL.js.map → WebGLSeriesRenderer-BXFfVudh.js.map} +1 -1
- package/dist/{WebGLSeriesRenderer-Hwer7mph.cjs → WebGLSeriesRenderer-DaTDdW4O.cjs} +3 -3
- package/dist/{WebGLSeriesRenderer-Hwer7mph.cjs.map → WebGLSeriesRenderer-DaTDdW4O.cjs.map} +1 -1
- package/dist/axis/GridRenderer.d.ts +3 -1
- package/dist/axis/GridRenderer.d.ts.map +1 -1
- package/dist/axis/PriceAxis.d.ts +28 -0
- package/dist/axis/PriceAxis.d.ts.map +1 -1
- package/dist/axis/TimeAxis.d.ts +16 -0
- package/dist/axis/TimeAxis.d.ts.map +1 -1
- package/dist/axis/gridLines.d.ts +11 -1
- package/dist/axis/gridLines.d.ts.map +1 -1
- package/dist/axis/timeMarks.d.ts +75 -0
- package/dist/axis/timeMarks.d.ts.map +1 -0
- package/dist/engine/RenderEngine.d.ts.map +1 -1
- package/dist/engine/gpu.d.ts +3 -0
- package/dist/engine/gpu.d.ts.map +1 -1
- package/dist/gpuContexts-BN9YuYEa.cjs +2 -0
- package/dist/gpuContexts-BN9YuYEa.cjs.map +1 -0
- package/dist/{gpuContexts-B3iynnAn.js → gpuContexts-BXj2qguo.js} +39 -27
- package/dist/gpuContexts-BXj2qguo.js.map +1 -0
- package/dist/index.cjs +5 -5
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +2261 -2028
- package/dist/index.js.map +1 -1
- package/dist/ui/SessionBreaks.d.ts +2 -0
- package/dist/ui/SessionBreaks.d.ts.map +1 -1
- package/dist/viewport/Viewport.d.ts.map +1 -1
- package/package.json +2 -2
- package/dist/gpuContexts-B3iynnAn.js.map +0 -1
- package/dist/gpuContexts-X-Q3OVWF.cjs +0 -2
- package/dist/gpuContexts-X-Q3OVWF.cjs.map +0 -1
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
import { ViewportState, Theme, ResolvedLineLook } from '@tradecanvas/commons';
|
|
2
|
+
import { GridMarks } from './gridLines.js';
|
|
2
3
|
export declare class GridRenderer {
|
|
3
4
|
private visible;
|
|
4
5
|
setVisible(v: boolean): void;
|
|
5
6
|
isVisible(): boolean;
|
|
6
|
-
|
|
7
|
+
/** `marks`: where the axes put their labels, for the lines to agree with them. */
|
|
8
|
+
render(ctx: CanvasRenderingContext2D, viewport: ViewportState, theme: Theme, marks?: GridMarks): void;
|
|
7
9
|
}
|
|
8
10
|
/** The grid's looks each way: the resolved style's, or the theme's grid colour, solid, 1 px. */
|
|
9
11
|
export declare function gridLooks(theme: Theme): {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"GridRenderer.d.ts","sourceRoot":"","sources":["../../src/axis/GridRenderer.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,KAAK,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;
|
|
1
|
+
{"version":3,"file":"GridRenderer.d.ts","sourceRoot":"","sources":["../../src/axis/GridRenderer.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,KAAK,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AAEnF,OAAO,EAAa,KAAK,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAK3D,qBAAa,YAAY;IACvB,OAAO,CAAC,OAAO,CAAQ;IAEvB,UAAU,CAAC,CAAC,EAAE,OAAO,GAAG,IAAI;IAC5B,SAAS,IAAI,OAAO;IAEpB,kFAAkF;IAClF,MAAM,CAAC,GAAG,EAAE,wBAAwB,EAAE,QAAQ,EAAE,aAAa,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,CAAC,EAAE,SAAS,GAAG,IAAI;CA4CtG;AAED,gGAAgG;AAChG,wBAAgB,SAAS,CAAC,KAAK,EAAE,KAAK,GAAG;IAAE,UAAU,EAAE,gBAAgB,CAAC;IAAC,QAAQ,EAAE,gBAAgB,CAAA;CAAE,CAGpG;AAED;;;GAGG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,KAAK,GAAG,OAAO,CAIjD"}
|
package/dist/axis/PriceAxis.d.ts
CHANGED
|
@@ -4,6 +4,16 @@ import { ViewportState, Theme } from '@tradecanvas/commons';
|
|
|
4
4
|
* chart's price format (`viewport.formatPrice`), else in decimals.
|
|
5
5
|
*/
|
|
6
6
|
export declare function priceScaleText(price: number, viewport: ViewportState, precision: number, locale: string): string;
|
|
7
|
+
/** The spacing (px) price labels aim for: how many fit follows the scale's height. */
|
|
8
|
+
export declare const PRICE_LABEL_SPACING_PX = 56;
|
|
9
|
+
/** Price labels never closer than this (px). */
|
|
10
|
+
export declare const MIN_PRICE_LABEL_GAP_PX = 30;
|
|
11
|
+
/** How many ticks a scale `height` px tall aims for (the `maxTicks` of `computeTickStep`). */
|
|
12
|
+
export declare function tickTarget(height: number): number;
|
|
13
|
+
/** A round step for `min`..`max` on a scale `height` px tall, its labels at least `MIN_PRICE_LABEL_GAP_PX` apart. */
|
|
14
|
+
export declare function roundStep(min: number, max: number, height: number): number;
|
|
15
|
+
/** The multiples of `step` from `min` to `max`, by index (adding the step up drifts: 0.1 × 3 passes 0.3). */
|
|
16
|
+
export declare function stepTicks(min: number, max: number, step: number): number[];
|
|
7
17
|
export declare class PriceAxis {
|
|
8
18
|
private locale;
|
|
9
19
|
private reservedPrice;
|
|
@@ -20,6 +30,24 @@ export declare class PriceAxis {
|
|
|
20
30
|
* (a flat or deeply zoomed range), the plain step in the decimals it needs.
|
|
21
31
|
*/
|
|
22
32
|
private scale;
|
|
33
|
+
/**
|
|
34
|
+
* The prices the scale marks for the range on view, low to high: where its
|
|
35
|
+
* labels and the grid's lines go. As many as the height fits. On a
|
|
36
|
+
* percent or indexed scale, round percents or index points; on a log
|
|
37
|
+
* scale, round prices whose step grows with the price, so its whole
|
|
38
|
+
* height is labelled.
|
|
39
|
+
*/
|
|
40
|
+
ticks(viewport: ViewportState): number[];
|
|
41
|
+
/** Ticks at round values of `value = price × 100 / baseline` (less 100 for percent). */
|
|
42
|
+
private rebasedTicks;
|
|
43
|
+
/**
|
|
44
|
+
* Ticks down a log scale from the top: from each tick, the next goes near
|
|
45
|
+
* the price `PRICE_LABEL_SPACING_PX` below it, at a round multiple of a
|
|
46
|
+
* step no larger than that drop (on the symbol's price grid), so labels
|
|
47
|
+
* stay as far apart at the bottom as at the top (100k, 40k, 10k, 4k…).
|
|
48
|
+
* One closer than `MIN_PRICE_LABEL_GAP_PX` to the last is skipped.
|
|
49
|
+
*/
|
|
50
|
+
private logTicks;
|
|
23
51
|
/** A price as this scale writes it now (to measure the axis by). */
|
|
24
52
|
labelText(price: number, viewport: ViewportState): string;
|
|
25
53
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"PriceAxis.d.ts","sourceRoot":"","sources":["../../src/axis/PriceAxis.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,KAAK,EAAE,MAAM,sBAAsB,CAAC;AAGjE;;;GAGG;AACH,wBAAgB,cAAc,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,CAMhH;
|
|
1
|
+
{"version":3,"file":"PriceAxis.d.ts","sourceRoot":"","sources":["../../src/axis/PriceAxis.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,KAAK,EAAE,MAAM,sBAAsB,CAAC;AAGjE;;;GAGG;AACH,wBAAgB,cAAc,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,CAMhH;AA0BD,sFAAsF;AACtF,eAAO,MAAM,sBAAsB,KAAK,CAAC;AACzC,gDAAgD;AAChD,eAAO,MAAM,sBAAsB,KAAK,CAAC;AAKzC,8FAA8F;AAC9F,wBAAgB,UAAU,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAEjD;AAkBD,qHAAqH;AACrH,wBAAgB,SAAS,CAAC,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,CAM1E;AAED,6GAA6G;AAC7G,wBAAgB,SAAS,CAAC,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,EAAE,CAY1E;AAOD,qBAAa,SAAS;IACpB,OAAO,CAAC,MAAM,CAAW;IACzB,OAAO,CAAC,aAAa,CAAsC;IAC3D,OAAO,CAAC,SAAS,CAAuB;IACxC,OAAO,CAAC,IAAI,CAAuB;IAEnC,iGAAiG;IACjG,iBAAiB,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,GAAG,IAAI;IAIjD,qGAAqG;IACrG,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,GAAG,IAAI;IAIvC;;;;;OAKG;IACH,OAAO,CAAC,KAAK;IAUb;;;;;;OAMG;IACH,KAAK,CAAC,QAAQ,EAAE,aAAa,GAAG,MAAM,EAAE;IAUxC,wFAAwF;IACxF,OAAO,CAAC,YAAY;IAWpB;;;;;;OAMG;IACH,OAAO,CAAC,QAAQ;IA4BhB,oEAAoE;IACpE,SAAS,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,aAAa,GAAG,MAAM;IAIzD;;;OAGG;IACH,wBAAwB,CAAC,QAAQ,EAAE,CAAC,MAAM,MAAM,GAAG,IAAI,CAAC,GAAG,IAAI,GAAG,IAAI;IAItE,SAAS,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI;IAI/B;;;OAGG;IACH,MAAM,CACJ,GAAG,EAAE,wBAAwB,EAC7B,QAAQ,EAAE,aAAa,EACvB,KAAK,EAAE,KAAK,EACZ,IAAI,GAAE,OAAO,GAAG,MAAgB;IAChC,kGAAkG;IAClG,KAAK,GAAE,SAAS,MAAM,EAAO,GAC5B,IAAI;CAwDR"}
|
package/dist/axis/TimeAxis.d.ts
CHANGED
|
@@ -1,11 +1,18 @@
|
|
|
1
1
|
import { ViewportState, Theme, DataSeries, TimeFormatter, TimeZoneSetting } from '@tradecanvas/commons';
|
|
2
|
+
import { TimeMark } from './timeMarks.js';
|
|
2
3
|
/** Space kept between the last tick label and the timezone tag. */
|
|
3
4
|
export declare const TZ_LABEL_GAP_PX = 8;
|
|
5
|
+
/** Labels (and grid columns) at least this far apart, px. */
|
|
6
|
+
export declare const MIN_LABEL_SPACING_PX = 80;
|
|
4
7
|
export declare class TimeAxis {
|
|
5
8
|
/** An IANA zone, a fixed UTC offset in minutes, or null for the browser's zone. */
|
|
6
9
|
private tz;
|
|
7
10
|
private timeFormatter;
|
|
8
11
|
private timesPastData;
|
|
12
|
+
private locale;
|
|
13
|
+
private readonly marker;
|
|
14
|
+
/** The locale month names are written in. */
|
|
15
|
+
setLocale(locale: string): void;
|
|
9
16
|
setTimezoneOffset(tz: TimeZoneSetting): void;
|
|
10
17
|
/** Labels in your words, or null for its own. */
|
|
11
18
|
setTimeFormatter(formatter: TimeFormatter | null): void;
|
|
@@ -16,6 +23,15 @@ export declare class TimeAxis {
|
|
|
16
23
|
*/
|
|
17
24
|
setTimesPastData(on: boolean): void;
|
|
18
25
|
getTimesPastData(): boolean;
|
|
26
|
+
/**
|
|
27
|
+
* The slots labelled on view, the grid's columns with them: the bars that
|
|
28
|
+
* start the largest calendar steps, at least `MIN_LABEL_SPACING_PX` apart.
|
|
29
|
+
* Nothing left of the oldest bar, whose history isn't loaded; past the
|
|
30
|
+
* newest, the future's slots when times are extrapolated there.
|
|
31
|
+
*/
|
|
32
|
+
marks(viewport: ViewportState, data: DataSeries): TimeMark[];
|
|
33
|
+
/** "2024" where a year starts, "Mar" a month, "15" a day, "13:30" within a day. */
|
|
34
|
+
private label;
|
|
19
35
|
render(ctx: CanvasRenderingContext2D, viewport: ViewportState, theme: Theme, data: DataSeries, axisYOverride?: number): void;
|
|
20
36
|
}
|
|
21
37
|
//# sourceMappingURL=TimeAxis.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TimeAxis.d.ts","sourceRoot":"","sources":["../../src/axis/TimeAxis.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,KAAK,EAAE,UAAU,
|
|
1
|
+
{"version":3,"file":"TimeAxis.d.ts","sourceRoot":"","sources":["../../src/axis/TimeAxis.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,KAAK,EAAE,UAAU,EAAE,aAAa,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AAG7G,OAAO,EAAoD,KAAK,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAIjG,mEAAmE;AACnE,eAAO,MAAM,eAAe,IAAI,CAAC;AAEjC,6DAA6D;AAC7D,eAAO,MAAM,oBAAoB,KAAK,CAAC;AAsBvC,qBAAa,QAAQ;IACnB,mFAAmF;IACnF,OAAO,CAAC,EAAE,CAAyB;IACnC,OAAO,CAAC,aAAa,CAA8B;IACnD,OAAO,CAAC,aAAa,CAAQ;IAC7B,OAAO,CAAC,MAAM,CAAW;IACzB,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAoB;IAE3C,6CAA6C;IAC7C,SAAS,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI;IAI/B,iBAAiB,CAAC,EAAE,EAAE,eAAe,GAAG,IAAI;IAI5C,iDAAiD;IACjD,gBAAgB,CAAC,SAAS,EAAE,aAAa,GAAG,IAAI,GAAG,IAAI;IAIvD;;;;OAIG;IACH,gBAAgB,CAAC,EAAE,EAAE,OAAO,GAAG,IAAI;IAInC,gBAAgB,IAAI,OAAO;IAI3B;;;;;OAKG;IACH,KAAK,CAAC,QAAQ,EAAE,aAAa,EAAE,IAAI,EAAE,UAAU,GAAG,QAAQ,EAAE;IAY5D,mFAAmF;IACnF,OAAO,CAAC,KAAK;IAWb,MAAM,CAAC,GAAG,EAAE,wBAAwB,EAAE,QAAQ,EAAE,aAAa,EAAE,KAAK,EAAE,KAAK,EAAE,IAAI,EAAE,UAAU,EAAE,aAAa,CAAC,EAAE,MAAM,GAAG,IAAI;CA6D7H"}
|
package/dist/axis/gridLines.d.ts
CHANGED
|
@@ -4,6 +4,16 @@ export interface GridLines {
|
|
|
4
4
|
horizontal: number[];
|
|
5
5
|
vertical: number[];
|
|
6
6
|
}
|
|
7
|
+
/**
|
|
8
|
+
* Where the axes put their labels: the grid draws its lines there, so lines
|
|
9
|
+
* and labels agree. Either can be left out for the grid's own even spacing.
|
|
10
|
+
*/
|
|
11
|
+
export interface GridMarks {
|
|
12
|
+
/** Prices the price axis labels. */
|
|
13
|
+
prices?: readonly number[];
|
|
14
|
+
/** Slots the time axis labels. */
|
|
15
|
+
slots?: readonly number[];
|
|
16
|
+
}
|
|
7
17
|
/** Where the grid lines go, for the 2D grid and the GPU alike. */
|
|
8
|
-
export declare function gridLines(viewport: ViewportState): GridLines;
|
|
18
|
+
export declare function gridLines(viewport: ViewportState, marks?: GridMarks): GridLines;
|
|
9
19
|
//# sourceMappingURL=gridLines.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"gridLines.d.ts","sourceRoot":"","sources":["../../src/axis/gridLines.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAI1D,kGAAkG;AAClG,MAAM,WAAW,SAAS;IACxB,UAAU,EAAE,MAAM,EAAE,CAAC;IACrB,QAAQ,EAAE,MAAM,EAAE,CAAC;CACpB;AAKD,kEAAkE;AAClE,wBAAgB,SAAS,CAAC,QAAQ,EAAE,aAAa,GAAG,SAAS,
|
|
1
|
+
{"version":3,"file":"gridLines.d.ts","sourceRoot":"","sources":["../../src/axis/gridLines.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAI1D,kGAAkG;AAClG,MAAM,WAAW,SAAS;IACxB,UAAU,EAAE,MAAM,EAAE,CAAC;IACrB,QAAQ,EAAE,MAAM,EAAE,CAAC;CACpB;AAED;;;GAGG;AACH,MAAM,WAAW,SAAS;IACxB,oCAAoC;IACpC,MAAM,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IAC3B,kCAAkC;IAClC,KAAK,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;CAC3B;AAKD,kEAAkE;AAClE,wBAAgB,SAAS,CAAC,QAAQ,EAAE,aAAa,EAAE,KAAK,GAAE,SAAc,GAAG,SAAS,CAiCnF"}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import { TimeZoneSetting, TimeParts } from '@tradecanvas/commons';
|
|
2
|
+
/**
|
|
3
|
+
* How much a bar's time stands out: the largest calendar step since the bar
|
|
4
|
+
* before it. A new year outranks a new month, a month a day, a day an hour,
|
|
5
|
+
* and among those a round one (a quarter, the 15th, noon, the half hour)
|
|
6
|
+
* the rest, so the marks that fit are the ones that say the most.
|
|
7
|
+
*/
|
|
8
|
+
export declare const MARK_WEIGHT: {
|
|
9
|
+
readonly year: 100;
|
|
10
|
+
readonly quarter: 91;
|
|
11
|
+
readonly month: 90;
|
|
12
|
+
readonly dayOfFive: 81;
|
|
13
|
+
readonly day: 80;
|
|
14
|
+
readonly hour12: 73;
|
|
15
|
+
readonly hour6: 72;
|
|
16
|
+
readonly hour3: 71;
|
|
17
|
+
readonly hour: 70;
|
|
18
|
+
readonly minute30: 63;
|
|
19
|
+
readonly minute15: 62;
|
|
20
|
+
readonly minute5: 61;
|
|
21
|
+
readonly minute: 60;
|
|
22
|
+
/** Bars within one minute (seconds, ticks): labelled with their seconds. */
|
|
23
|
+
readonly within: 50;
|
|
24
|
+
};
|
|
25
|
+
/** What a mark's label says: the year, the month, the day of the month, or the time. */
|
|
26
|
+
export type MarkKind = 'year' | 'month' | 'day' | 'time';
|
|
27
|
+
export declare function markKind(weight: number): MarkKind;
|
|
28
|
+
/** A slot the time axis labels and the grid draws a line down. */
|
|
29
|
+
export interface TimeMark {
|
|
30
|
+
/** The slot: a bar's index, or past the last bar, a slot in the future. */
|
|
31
|
+
index: number;
|
|
32
|
+
/** Its time in milliseconds, in UTC. */
|
|
33
|
+
time: number;
|
|
34
|
+
weight: number;
|
|
35
|
+
}
|
|
36
|
+
export interface TimeMarkQuery {
|
|
37
|
+
/** The slots on view. */
|
|
38
|
+
from: number;
|
|
39
|
+
to: number;
|
|
40
|
+
/** Slots between two marks at least. */
|
|
41
|
+
gapBars: number;
|
|
42
|
+
tz: TimeZoneSetting;
|
|
43
|
+
/** Whether the empty future right of the last bar gets marks (off for tick bars and bricks). */
|
|
44
|
+
timesPastData: boolean;
|
|
45
|
+
}
|
|
46
|
+
/** The weight of a bar at `cur` after one at `prev`; 0 for the first bar, which has nothing to stand out from. */
|
|
47
|
+
export declare function markWeight(prev: TimeParts | null, cur: TimeParts): number;
|
|
48
|
+
/**
|
|
49
|
+
* Picks the time axis's marks, and the grid's columns with them. Each bar is
|
|
50
|
+
* weighed once by the calendar step it starts; then, heaviest first, a bar
|
|
51
|
+
* becomes a mark unless one is already closer than the gap. Marks belong to
|
|
52
|
+
* bars, not to slots on screen: panning moves them with their bars, and
|
|
53
|
+
* history put in front leaves them where they were. Both steps are cached:
|
|
54
|
+
* weights while the series is the same, marks while the gap is too.
|
|
55
|
+
*/
|
|
56
|
+
export declare class TimeMarker {
|
|
57
|
+
private weights;
|
|
58
|
+
private times;
|
|
59
|
+
/** What `weights` and `times` were made for: the bars weighed, the zone, the slots. */
|
|
60
|
+
private weighed;
|
|
61
|
+
private chosen;
|
|
62
|
+
private chosenFor;
|
|
63
|
+
marks(data: ArrayLike<{
|
|
64
|
+
time: number;
|
|
65
|
+
}>, query: TimeMarkQuery): TimeMark[];
|
|
66
|
+
/**
|
|
67
|
+
* Weigh the bars and the future slots. A series rebuilt as a new array (a
|
|
68
|
+
* derived chart type on every tick) keeps its weights while its times are
|
|
69
|
+
* the same; bars appended are weighed on from the last one kept. Only
|
|
70
|
+
* history put in front, or another zone, weighs everything again.
|
|
71
|
+
*/
|
|
72
|
+
private weigh;
|
|
73
|
+
private choose;
|
|
74
|
+
}
|
|
75
|
+
//# sourceMappingURL=timeMarks.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"timeMarks.d.ts","sourceRoot":"","sources":["../../src/axis/timeMarks.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AAC5D,OAAO,EAA0B,KAAK,SAAS,EAAE,MAAM,sBAAsB,CAAC;AAG9E;;;;;GAKG;AACH,eAAO,MAAM,WAAW;;;;;;;;;;;;;;IActB,4EAA4E;;CAEpE,CAAC;AAKX,wFAAwF;AACxF,MAAM,MAAM,QAAQ,GAAG,MAAM,GAAG,OAAO,GAAG,KAAK,GAAG,MAAM,CAAC;AAEzD,wBAAgB,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,QAAQ,CAKjD;AAED,kEAAkE;AAClE,MAAM,WAAW,QAAQ;IACvB,2EAA2E;IAC3E,KAAK,EAAE,MAAM,CAAC;IACd,wCAAwC;IACxC,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,aAAa;IAC5B,yBAAyB;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,EAAE,EAAE,MAAM,CAAC;IACX,wCAAwC;IACxC,OAAO,EAAE,MAAM,CAAC;IAChB,EAAE,EAAE,eAAe,CAAC;IACpB,gGAAgG;IAChG,aAAa,EAAE,OAAO,CAAC;CACxB;AAED,kHAAkH;AAClH,wBAAgB,UAAU,CAAC,IAAI,EAAE,SAAS,GAAG,IAAI,EAAE,GAAG,EAAE,SAAS,GAAG,MAAM,CAezE;AAaD;;;;;;;GAOG;AACH,qBAAa,UAAU;IACrB,OAAO,CAAC,OAAO,CAAqB;IACpC,OAAO,CAAC,KAAK,CAAgB;IAC7B,uFAAuF;IACvF,OAAO,CAAC,OAAO,CAAoF;IACnG,OAAO,CAAC,MAAM,CAAiC;IAC/C,OAAO,CAAC,SAAS,CAAyE;IAE1F,KAAK,CAAC,IAAI,EAAE,SAAS,CAAC;QAAE,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC,EAAE,KAAK,EAAE,aAAa,GAAG,QAAQ,EAAE;IA2B1E;;;;;OAKG;IACH,OAAO,CAAC,KAAK;IAiCb,OAAO,CAAC,MAAM;CAkBf"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"RenderEngine.d.ts","sourceRoot":"","sources":["../../src/engine/RenderEngine.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAC;AACjD,OAAO,KAAK,EAAE,IAAI,EAAE,aAAa,EAAE,KAAK,EAAE,UAAU,EAAE,IAAI,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAC;AAIpG,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAEjD,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAC7C,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAE7C,OAAO,KAAK,EAAwC,WAAW,EAAE,MAAM,UAAU,CAAC;AAGlF,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,4BAA4B,CAAC;AACzE,OAAO,EAAe,KAAK,YAAY,EAAE,MAAM,yBAAyB,CAAC;
|
|
1
|
+
{"version":3,"file":"RenderEngine.d.ts","sourceRoot":"","sources":["../../src/engine/RenderEngine.ts"],"names":[],"mappings":"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"}
|
package/dist/engine/gpu.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { GridMarks } from '../axis/gridLines.js';
|
|
1
2
|
import { ChartOptions, DataSeries, Rect, Theme, ViewportState } from '@tradecanvas/commons';
|
|
2
3
|
/** Which renderer draws the chart: Canvas 2D, WebGL, or WebGL where it's fast and Canvas 2D otherwise. */
|
|
3
4
|
export type RendererMode = NonNullable<ChartOptions['renderer']>;
|
|
@@ -15,6 +16,8 @@ export interface GpuRect {
|
|
|
15
16
|
/** What goes under the bars, unclipped: the grid, then filled rectangles (session shading, break lines). */
|
|
16
17
|
export interface GpuBackground {
|
|
17
18
|
grid: boolean;
|
|
19
|
+
/** Where the axes label: the grid's lines go there. */
|
|
20
|
+
marks?: GridMarks;
|
|
18
21
|
rects: readonly GpuRect[];
|
|
19
22
|
}
|
|
20
23
|
/**
|
package/dist/engine/gpu.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"gpu.d.ts","sourceRoot":"","sources":["../../src/engine/gpu.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,UAAU,EAAE,IAAI,EAAE,KAAK,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAEjG,0GAA0G;AAC1G,MAAM,MAAM,YAAY,GAAG,WAAW,CAAC,YAAY,CAAC,UAAU,CAAC,CAAC,CAAC;AAEjE,gGAAgG;AAChG,MAAM,WAAW,OAAO;IACtB,CAAC,EAAE,MAAM,CAAC;IACV,CAAC,EAAE,MAAM,CAAC;IACV,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,kGAAkG;IAClG,IAAI,CAAC,EAAE,SAAS,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAClC;AAED,4GAA4G;AAC5G,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,OAAO,CAAC;IACd,KAAK,EAAE,SAAS,OAAO,EAAE,CAAC;CAC3B;AAED;;;GAGG;AACH,MAAM,WAAW,WAAW;IAC1B;;;;OAIG;IACH,MAAM,CAAC,IAAI,EAAE,IAAI,EAAE,OAAO,CAAC,EAAE;QAAE,IAAI,CAAC,EAAE,OAAO,CAAA;KAAE,GAAG,SAAS,CAAC;CAC7D;AAED,MAAM,WAAW,SAAS;IACxB;;;;OAIG;IACH,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC,EAAE,wBAAwB,KAAK,IAAI,GAAG,OAAO,CAAC;IAC3D,iFAAiF;IACjF,QAAQ,CAAC,CAAC,EAAE,wBAAwB,GAAG,IAAI,CAAC;CAC7C;AAED,uDAAuD;AACvD,MAAM,WAAW,QAAQ;IACvB,IAAI,EAAE,UAAU,CAAC;IACjB,QAAQ,EAAE,aAAa,CAAC;IACxB,KAAK,EAAE,KAAK,CAAC;IACb,mCAAmC;IACnC,GAAG,EAAE,MAAM,CAAC;IACZ,uCAAuC;IACvC,OAAO,EAAE,OAAO,CAAC;IACjB,+DAA+D;IAC/D,MAAM,EAAE;QAAE,WAAW,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAC;IACvC,yEAAyE;IACzE,UAAU,EAAE,aAAa,GAAG,IAAI,CAAC;IACjC,6EAA6E;IAC7E,QAAQ,CAAC,EAAE,WAAW,GAAG,IAAI,CAAC;IAC9B;;;OAGG;IACH,KAAK,CAAC,EAAE,WAAW,GAAG,IAAI,CAAC;CAC5B;AAED,uDAAuD;AACvD,MAAM,WAAW,QAAQ;IACvB,MAAM,EAAE,OAAO,CAAC;IAChB,MAAM,EAAE,OAAO,CAAC;IAChB,UAAU,EAAE,OAAO,CAAC;IACpB,kCAAkC;IAClC,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,+BAA+B;IAC/B,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB;AAED;;;;GAIG;AACH,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,MAAM,EAAE,iBAAiB,CAAC;IACnC,gDAAgD;IAChD,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,MAAM,CAAC,KAAK,EAAE,QAAQ,GAAG,QAAQ,CAAC;IAClC;;;OAGG;IACH,QAAQ,CAAC,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,EAAE,wBAAwB,GAAG,IAAI,GAAG,WAAW,CAAC;IAC9E,uFAAuF;IACvF,MAAM,CAAC,QAAQ,EAAE,MAAM,IAAI,GAAG,IAAI,CAAC;IACnC,iFAAiF;IACjF,UAAU,CAAC,CAAC,QAAQ,EAAE,MAAM,IAAI,GAAG,IAAI,CAAC;IACxC,OAAO,IAAI,IAAI,CAAC;CACjB"}
|
|
1
|
+
{"version":3,"file":"gpu.d.ts","sourceRoot":"","sources":["../../src/engine/gpu.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAC;AACtD,OAAO,KAAK,EAAE,YAAY,EAAE,UAAU,EAAE,IAAI,EAAE,KAAK,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAEjG,0GAA0G;AAC1G,MAAM,MAAM,YAAY,GAAG,WAAW,CAAC,YAAY,CAAC,UAAU,CAAC,CAAC,CAAC;AAEjE,gGAAgG;AAChG,MAAM,WAAW,OAAO;IACtB,CAAC,EAAE,MAAM,CAAC;IACV,CAAC,EAAE,MAAM,CAAC;IACV,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,kGAAkG;IAClG,IAAI,CAAC,EAAE,SAAS,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAClC;AAED,4GAA4G;AAC5G,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,OAAO,CAAC;IACd,uDAAuD;IACvD,KAAK,CAAC,EAAE,SAAS,CAAC;IAClB,KAAK,EAAE,SAAS,OAAO,EAAE,CAAC;CAC3B;AAED;;;GAGG;AACH,MAAM,WAAW,WAAW;IAC1B;;;;OAIG;IACH,MAAM,CAAC,IAAI,EAAE,IAAI,EAAE,OAAO,CAAC,EAAE;QAAE,IAAI,CAAC,EAAE,OAAO,CAAA;KAAE,GAAG,SAAS,CAAC;CAC7D;AAED,MAAM,WAAW,SAAS;IACxB;;;;OAIG;IACH,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC,EAAE,wBAAwB,KAAK,IAAI,GAAG,OAAO,CAAC;IAC3D,iFAAiF;IACjF,QAAQ,CAAC,CAAC,EAAE,wBAAwB,GAAG,IAAI,CAAC;CAC7C;AAED,uDAAuD;AACvD,MAAM,WAAW,QAAQ;IACvB,IAAI,EAAE,UAAU,CAAC;IACjB,QAAQ,EAAE,aAAa,CAAC;IACxB,KAAK,EAAE,KAAK,CAAC;IACb,mCAAmC;IACnC,GAAG,EAAE,MAAM,CAAC;IACZ,uCAAuC;IACvC,OAAO,EAAE,OAAO,CAAC;IACjB,+DAA+D;IAC/D,MAAM,EAAE;QAAE,WAAW,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAC;IACvC,yEAAyE;IACzE,UAAU,EAAE,aAAa,GAAG,IAAI,CAAC;IACjC,6EAA6E;IAC7E,QAAQ,CAAC,EAAE,WAAW,GAAG,IAAI,CAAC;IAC9B;;;OAGG;IACH,KAAK,CAAC,EAAE,WAAW,GAAG,IAAI,CAAC;CAC5B;AAED,uDAAuD;AACvD,MAAM,WAAW,QAAQ;IACvB,MAAM,EAAE,OAAO,CAAC;IAChB,MAAM,EAAE,OAAO,CAAC;IAChB,UAAU,EAAE,OAAO,CAAC;IACpB,kCAAkC;IAClC,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,+BAA+B;IAC/B,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB;AAED;;;;GAIG;AACH,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,MAAM,EAAE,iBAAiB,CAAC;IACnC,gDAAgD;IAChD,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,MAAM,CAAC,KAAK,EAAE,QAAQ,GAAG,QAAQ,CAAC;IAClC;;;OAGG;IACH,QAAQ,CAAC,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,EAAE,wBAAwB,GAAG,IAAI,GAAG,WAAW,CAAC;IAC9E,uFAAuF;IACvF,MAAM,CAAC,QAAQ,EAAE,MAAM,IAAI,GAAG,IAAI,CAAC;IACnC,iFAAiF;IACjF,UAAU,CAAC,CAAC,QAAQ,EAAE,MAAM,IAAI,GAAG,IAAI,CAAC;IACxC,OAAO,IAAI,IAAI,CAAC;CACjB"}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
let e=require(`@tradecanvas/commons`);function t(e,t){return e*(t.barWidth+t.barSpacing)-t.offset+t.chartRect.x+t.barWidth/2}function n(e,t){let{min:n,max:r}=t.priceRange,{y:i,height:a}=t.chartRect,o;if(t.logScale&&n>0&&r>0){let t=Math.log(n),s=Math.log(r)-t;if(s===0)return i+a/2;o=(Math.log(Math.max(e,2**-52))-t)/s}else{let t=r-n;if(t===0)return i+a/2;o=(e-n)/t}return i+a*(t.invertScale?o:1-o)}function r(e){let{min:t,max:n}=e.priceRange,{y:r,height:i}=e.chartRect,a=e.invertScale===!0;if(e.logScale&&t>0&&n>0){let e=Math.log(t),o=Math.log(n)-e;if(o===0)return()=>r+i/2;let s=i/o,c=r+i;return a?t=>r+(Math.log(Math.max(t,2**-52))-e)*s:t=>c-(Math.log(Math.max(t,2**-52))-e)*s}let o=n-t;if(o===0)return()=>r+i/2;let s=i/o;return a?e=>r+(e-t)*s:e=>r+(n-e)*s}function i(e,t,n,r){let{min:i,max:a}=n.priceRange,o=(a-i)/t,s=r(i+e*o),c=r(i+(e+1)*o);return{top:Math.min(s,c),height:Math.abs(s-c),mid:(s+c)/2}}function a(e,t){let n=t.barWidth+t.barSpacing;return Math.round((e-t.chartRect.x-t.barWidth/2+t.offset)/n)}function o(e,t){let{min:n,max:r}=t.priceRange,i=(e-t.chartRect.y)/t.chartRect.height,a=t.invertScale?i:1-i;if(t.logScale&&n>0&&r>0){let e=Math.log(n);return Math.exp(e+(Math.log(r)-e)*a)}return n+(r-n)*a}var s=new WeakMap;function c(e){let t=e.length;if(t<2)return 0;let n=s.get(e);if(n&&n.length===t)return n.step;let r=[];for(let n=Math.max(1,t-20);n<t;n++)r.push(e[n].time-e[n-1].time);r.sort((e,t)=>e-t);let i=Math.max(0,r[r.length>>1]);return s.set(e,{length:t,step:i}),i}var l=100,u=new WeakMap;function d(e){let t=e.length;if(t<2)return 0;let n=Math.min(t-1,l),r=u.get(e);if(r&&r.length===t&&r.first===e[0].time&&r.end===e[n].time)return r.step;let i=(e[n].time-e[0].time)/n,a=i>0?i:c(e);return u.set(e,{length:t,first:e[0].time,end:e[n].time,step:a}),a}function f(t){return c(t)*(0,e.barTimeUnit)(t)}function p(e,t){let n=t.length;if(n===0)return e;let r=n-1;if(e>r)return t[r].time+(e-r)*c(t);if(e<0)return t[0].time+e*d(t);let i=Math.floor(e);return i===e||i>=r?t[i].time:t[i].time+(e-i)*(t[i+1].time-t[i].time)}function m(e,t){if(t.length===0)return-1;let n=t[0].time,r=t.length-1,i=t[r].time;if(e<=n||e>=i){if(e===n)return 0;if(e===i)return r;let a=e<n?d(t):c(t);return a<=0?e<n?0:r:e<n?(e-n)/a:r+(e-i)/a}let a=0,o=t.length-1;for(;a<=o;){let n=a+o>>>1;if(t[n].time===e)return n;t[n].time<e?a=n+1:o=n-1}if(a>=t.length)return t.length-1;if(o<0)return 0;let s=t[o].time,l=t[a].time,u=l===s?0:(e-s)/(l-s);return o+u}function h(e,t){let n=t.data;return n&&n.length>0?m(e,n):e}function g(e,n){return t(h(e,n),n)}function _(e,t){let n=a(e,t),r=t.data;return r&&r.length>0?p(n,r):n}var v=.5037;function y(e){return Math.floor(e+v)}function b(e){let t=typeof e.getTransform==`function`?e.getTransform():void 0;return{a:t&&Number.isFinite(t.a)&&t.a>0?t.a:1,d:t&&Number.isFinite(t.d)&&t.d>0?t.d:1,e:t&&Number.isFinite(t.e)?t.e:0,f:t&&Number.isFinite(t.f)?t.f:0}}function x(e,t){let{a:n,d:r,e:i,f:a}=b(e);e.save(),e.setTransform(1,0,0,1,0,0);try{return t({ratio:n,x:e=>y(e*n+i),y:e=>y(e*r+a),left:(e,t)=>y(e*n+i-t/2)})}finally{e.restore()}}function S(e,t){let n=Math.max(1,Math.floor(t)),r=Math.max(n,Math.round(e*t));return(r-n)%2!=0&&--r,{body:Math.max(r,n),wick:n}}function C(e,t,n,r){let i=Math.max(1,Math.round(t*n)),a=i%2?.5:0;return{at:(y(e*n+r-a)+a-r)/n,width:i/n}}function w(e,t,n){let r=b(e),i=C(t,n,r.d,r.f);return{y:i.at,width:i.width}}function T(e,t,n){let r=b(e),i=C(t,n,r.a,r.e);return{x:i.at,width:i.width}}var E=1;function D(e){return e.barWidth<1}function O(e,t,n,r,i){let a=Math.min(n,e.length-1);if(t>a)return;let o={x:0,open:0,high:0,low:0,close:0,volume:0},s=!1;for(let n=Math.max(0,t);n<=a;n++){let t=e[n],a=Math.floor(r(n));s&&a!==o.x&&(i(o),s=!1),s?(t.high>o.high&&(o.high=t.high),t.low<o.low&&(o.low=t.low),t.volume>o.volume&&(o.volume=t.volume)):(o.x=a,o.open=t.open,o.high=t.high,o.low=t.low,o.volume=t.volume,s=!0),o.close=t.close}s&&i(o)}function k(e,t,n,i,a){let{from:o,to:s}=n.visibleRange,c=n.barWidth+n.barSpacing,l=-n.offset+n.chartRect.x+n.barWidth/2,u=r(n);x(e,n=>{let r=new Path2D,d=new Path2D;O(t,o,s,e=>e*c+l,e=>{let t=n.y(u(e.high)),i=n.y(u(e.low)),a=n.x(e.x),o=Math.max(1,n.x(e.x+1)-a);(e.close>=e.open?r:d).rect(a,Math.min(t,i),o,Math.max(Math.abs(i-t),1))}),e.fillStyle=i,e.fill(r),e.fillStyle=a,e.fill(d)})}var A=80;function j(t,n={}){let{chartRect:i,priceRange:a}=t;if(a.max-a.min<=0)return{horizontal:[],vertical:[]};let o=r(t),s=[];if(n.prices)for(let e of n.prices)s.push(Math.round(o(e))+.5);else{let t=(0,e.computeTickStep)(a.min,a.max,8),n=Math.ceil(a.min/t)*t;for(let e=0;n+e*t<=a.max;e++)s.push(Math.round(o(n+e*t))+.5)}let c=[],l=t.barWidth+t.barSpacing,u=-t.offset+i.x+t.barWidth/2;if(n.slots){for(let e of n.slots)c.push(Math.round(e*l+u)+.5);return{horizontal:s,vertical:c}}let d=Math.max(1,Math.ceil(A/l)),f=Math.floor(t.offset/l),p=Math.ceil((t.offset+i.width)/l);for(let e=f;e<=p;e++)e%d===0&&c.push(Math.round(e*l+u)+.5);return{horizontal:s,vertical:c}}var M=[4,4],N=class{visible=!0;setVisible(e){this.visible=e}isVisible(){return this.visible}render(e,t,n,r){if(!this.visible)return;let{chartRect:i}=t,{horizontal:a,vertical:o}=j(t,r),s=P(n),c=s.horizontal,l=s.vertical;if(c.visible&&l.visible&&c.color===l.color&&c.style===l.style&&c.width===l.width){I(e,c,()=>{for(let t of a){let n=L(t,c.width);e.moveTo(i.x,n),e.lineTo(i.x+i.width,n)}for(let t of o){let n=L(t,l.width);e.moveTo(n,i.y),e.lineTo(n,i.y+i.height)}}),e.setLineDash([]);return}s.horizontal.visible&&a.length>0&&I(e,s.horizontal,()=>{for(let t of a){let n=L(t,s.horizontal.width);e.moveTo(i.x,n),e.lineTo(i.x+i.width,n)}}),s.vertical.visible&&o.length>0&&I(e,s.vertical,()=>{for(let t of o){let n=L(t,s.vertical.width);e.moveTo(n,i.y),e.lineTo(n,i.y+i.height)}}),e.setLineDash([])}};function P(e){let t={visible:!0,color:e.grid,style:`solid`,width:1};return e.style?.grid??{horizontal:t,vertical:t}}function F(e){let{horizontal:t,vertical:n}=P(e),r=[t,n].filter(e=>e.visible);return r.every(e=>e.style===`solid`&&e.width===1&&e.color===r[0].color)}function I(t,n,r){t.strokeStyle=n.color,t.lineWidth=n.width,t.setLineDash((0,e.lineDash)(n.style,M,n.width)),t.beginPath(),r(),t.stroke()}function L(e,t){return t%2==0?Math.round(e):e}var R=8,z=8,B=0,V=new Set;function H(e){z=Number.isNaN(e)?8:Math.max(0,Math.floor(e)),U()>0&&K()}function U(){return Math.max(0,z-B)}function W(){if(B>=z)return null;B++;let e=!1;return()=>{e||(e=!0,B--,K())}}function G(e){return V.add(e),()=>{V.delete(e)}}function K(){let e=[...V];V.clear();for(let t of e)try{t()}catch(e){queueMicrotask(()=>{throw e})}}Object.defineProperty(exports,`A`,{enumerable:!0,get:function(){return a}}),Object.defineProperty(exports,`C`,{enumerable:!0,get:function(){return d}}),Object.defineProperty(exports,`D`,{enumerable:!0,get:function(){return h}}),Object.defineProperty(exports,`E`,{enumerable:!0,get:function(){return r}}),Object.defineProperty(exports,`M`,{enumerable:!0,get:function(){return o}}),Object.defineProperty(exports,`O`,{enumerable:!0,get:function(){return g}}),Object.defineProperty(exports,`S`,{enumerable:!0,get:function(){return f}}),Object.defineProperty(exports,`T`,{enumerable:!0,get:function(){return n}}),Object.defineProperty(exports,`_`,{enumerable:!0,get:function(){return w}}),Object.defineProperty(exports,`a`,{enumerable:!0,get:function(){return G}}),Object.defineProperty(exports,`b`,{enumerable:!0,get:function(){return t}}),Object.defineProperty(exports,`c`,{enumerable:!0,get:function(){return P}}),Object.defineProperty(exports,`d`,{enumerable:!0,get:function(){return O}}),Object.defineProperty(exports,`f`,{enumerable:!0,get:function(){return D}}),Object.defineProperty(exports,`g`,{enumerable:!0,get:function(){return T}}),Object.defineProperty(exports,`h`,{enumerable:!0,get:function(){return S}}),Object.defineProperty(exports,`i`,{enumerable:!0,get:function(){return H}}),Object.defineProperty(exports,`j`,{enumerable:!0,get:function(){return _}}),Object.defineProperty(exports,`k`,{enumerable:!0,get:function(){return m}}),Object.defineProperty(exports,`l`,{enumerable:!0,get:function(){return j}}),Object.defineProperty(exports,`m`,{enumerable:!0,get:function(){return v}}),Object.defineProperty(exports,`n`,{enumerable:!0,get:function(){return W}}),Object.defineProperty(exports,`o`,{enumerable:!0,get:function(){return N}}),Object.defineProperty(exports,`p`,{enumerable:!0,get:function(){return k}}),Object.defineProperty(exports,`r`,{enumerable:!0,get:function(){return U}}),Object.defineProperty(exports,`s`,{enumerable:!0,get:function(){return F}}),Object.defineProperty(exports,`t`,{enumerable:!0,get:function(){return R}}),Object.defineProperty(exports,`u`,{enumerable:!0,get:function(){return E}}),Object.defineProperty(exports,`v`,{enumerable:!0,get:function(){return x}}),Object.defineProperty(exports,`w`,{enumerable:!0,get:function(){return i}}),Object.defineProperty(exports,`x`,{enumerable:!0,get:function(){return c}}),Object.defineProperty(exports,`y`,{enumerable:!0,get:function(){return p}});
|
|
2
|
+
//# sourceMappingURL=gpuContexts-BN9YuYEa.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"gpuContexts-BN9YuYEa.cjs","names":[],"sources":["../src/viewport/ScaleMapping.ts","../src/charts/pixelGrid.ts","../src/charts/denseBars.ts","../src/axis/gridLines.ts","../src/axis/GridRenderer.ts","../src/engine/gpuContexts.ts"],"sourcesContent":["import type { ViewportState } from '@tradecanvas/commons';\nimport { barTimeUnit } from '@tradecanvas/commons';\n\nexport function barIndexToX(index: number, viewport: ViewportState): number {\n const barUnit = viewport.barWidth + viewport.barSpacing;\n return index * barUnit - viewport.offset + viewport.chartRect.x + viewport.barWidth / 2;\n}\n\nexport function priceToY(price: number, viewport: ViewportState): number {\n const { min, max } = viewport.priceRange;\n const { y: top, height } = viewport.chartRect;\n let ratio: number;\n if (viewport.logScale && min > 0 && max > 0) {\n const logMin = Math.log(min);\n const logRange = Math.log(max) - logMin;\n if (logRange === 0) return top + height / 2;\n ratio = (Math.log(Math.max(price, Number.EPSILON)) - logMin) / logRange;\n } else {\n const range = max - min;\n if (range === 0) return top + height / 2;\n ratio = (price - min) / range;\n }\n return top + height * (viewport.invertScale ? ratio : 1 - ratio);\n}\n\n/**\n * `priceToY` for one frame, with the per-call work hoisted out: for renderers\n * that map every visible bar. Follows the log scale and the inverted scale.\n */\nexport function priceToYMapper(viewport: ViewportState): (price: number) => number {\n const { min, max } = viewport.priceRange;\n const { y: top, height } = viewport.chartRect;\n const invert = viewport.invertScale === true;\n if (viewport.logScale && min > 0 && max > 0) {\n const logMin = Math.log(min);\n const logRange = Math.log(max) - logMin;\n if (logRange === 0) return () => top + height / 2;\n const k = height / logRange;\n const bottom = top + height;\n return invert\n ? (price) => top + (Math.log(Math.max(price, Number.EPSILON)) - logMin) * k\n : (price) => bottom - (Math.log(Math.max(price, Number.EPSILON)) - logMin) * k;\n }\n const range = max - min;\n if (range === 0) return () => top + height / 2;\n const k = height / range;\n return invert ? (price) => top + (price - min) * k : (price) => top + (max - price) * k;\n}\n\n/**\n * Where bucket `b` of `count` equal price buckets across the price range sits\n * on screen (bucket 0 holds the lowest prices), on any scale. `toY` is the\n * frame's `priceToYMapper`.\n */\nexport function priceBucketRow(\n b: number,\n count: number,\n viewport: ViewportState,\n toY: (price: number) => number,\n): { top: number; height: number; mid: number } {\n const { min, max } = viewport.priceRange;\n const step = (max - min) / count;\n const yLow = toY(min + b * step);\n const yHigh = toY(min + (b + 1) * step);\n return { top: Math.min(yLow, yHigh), height: Math.abs(yLow - yHigh), mid: (yLow + yHigh) / 2 };\n}\n\nexport function xToBarIndex(x: number, viewport: ViewportState): number {\n const barUnit = viewport.barWidth + viewport.barSpacing;\n return Math.round((x - viewport.chartRect.x - viewport.barWidth / 2 + viewport.offset) / barUnit);\n}\n\nexport function yToPrice(y: number, viewport: ViewportState): number {\n const { min, max } = viewport.priceRange;\n const fromTop = (y - viewport.chartRect.y) / viewport.chartRect.height;\n const ratio = viewport.invertScale ? fromTop : 1 - fromTop;\n if (viewport.logScale && min > 0 && max > 0) {\n const logMin = Math.log(min);\n const logMax = Math.log(max);\n return Math.exp(logMin + (logMax - logMin) * ratio);\n }\n return min + (max - min) * ratio;\n}\n\ntype TimedSeries = ReadonlyArray<{ time: number }>;\n\nconst stepCache = new WeakMap<TimedSeries, { length: number; step: number }>();\n\n/**\n * Typical spacing between bar times — the median of the last ~20 intervals,\n * so a weekend or halt gap doesn't skew it. Used to place times beyond either\n * end of the data (the empty future the chart can be panned into). Cached per\n * series and length; 0 when there are fewer than two bars.\n */\nexport function barTimeStep(data: TimedSeries): number {\n const n = data.length;\n if (n < 2) return 0;\n const cached = stepCache.get(data);\n if (cached && cached.length === n) return cached.step;\n const diffs: number[] = [];\n for (let i = Math.max(1, n - 20); i < n; i++) diffs.push(data[i].time - data[i - 1].time);\n diffs.sort((a, b) => a - b);\n const step = Math.max(0, diffs[diffs.length >> 1]);\n stepCache.set(data, { length: n, step });\n return step;\n}\n\n/** Bars the spacing before the oldest bar is averaged over. */\nconst PAST_STEP_SAMPLE = 100;\n\nconst pastStepCache = new WeakMap<TimedSeries, { length: number; first: number; end: number; step: number }>();\n\n/**\n * The average spacing of the first bars, weekends, nights and halts\n * included: how far back in time a slot before the oldest bar goes, so an\n * extrapolated date lands about where the bars, once loaded, would put it.\n * Cached per series; `barTimeStep` when the first bars share one time, 0\n * when there are fewer than two bars.\n */\nexport function pastTimeStep(data: TimedSeries): number {\n const n = data.length;\n if (n < 2) return 0;\n const k = Math.min(n - 1, PAST_STEP_SAMPLE);\n const cached = pastStepCache.get(data);\n if (cached && cached.length === n && cached.first === data[0].time && cached.end === data[k].time) return cached.step;\n const average = (data[k].time - data[0].time) / k;\n const step = average > 0 ? average : barTimeStep(data);\n pastStepCache.set(data, { length: n, first: data[0].time, end: data[k].time, step });\n return step;\n}\n\n/** `barTimeStep` in milliseconds whatever unit the series uses (`barTimeUnit`). */\nexport function barTimeStepMs(data: TimedSeries): number {\n return barTimeStep(data) * barTimeUnit(data);\n}\n\n/**\n * Time at bar index `index`, extrapolated past either end of the data: by\n * `barTimeStep` into the future right of the newest bar, by `pastTimeStep`\n * before the oldest.\n */\nexport function barIndexToTime(index: number, data: TimedSeries): number {\n const n = data.length;\n if (n === 0) return index;\n const last = n - 1;\n if (index > last) return data[last].time + (index - last) * barTimeStep(data);\n if (index < 0) return data[0].time + index * pastTimeStep(data);\n const lo = Math.floor(index);\n if (lo === index || lo >= last) return data[lo].time;\n return data[lo].time + (index - lo) * (data[lo + 1].time - data[lo].time);\n}\n\n/**\n * Convert a bar timestamp to its data-array index via binary search.\n * Falls back to fractional interpolation when the timestamp falls between bars,\n * and extrapolates (as `barIndexToTime` does) for times beyond either end — so a drawing\n * anchored in the future keeps its place instead of collapsing onto the last bar.\n * Returns -1 if data is empty.\n */\nexport function timestampToBarIndex(timestamp: number, data: TimedSeries): number {\n if (data.length === 0) return -1;\n const first = data[0].time;\n const lastIdx = data.length - 1;\n const lastTime = data[lastIdx].time;\n if (timestamp <= first || timestamp >= lastTime) {\n if (timestamp === first) return 0;\n if (timestamp === lastTime) return lastIdx;\n const step = timestamp < first ? pastTimeStep(data) : barTimeStep(data);\n if (step <= 0) return timestamp < first ? 0 : lastIdx;\n return timestamp < first ? (timestamp - first) / step : lastIdx + (timestamp - lastTime) / step;\n }\n // Binary search\n let lo = 0, hi = data.length - 1;\n while (lo <= hi) {\n const mid = (lo + hi) >>> 1;\n if (data[mid].time === timestamp) return mid;\n if (data[mid].time < timestamp) lo = mid + 1;\n else hi = mid - 1;\n }\n // lo is the insertion point; interpolate between hi and lo\n if (lo >= data.length) return data.length - 1;\n if (hi < 0) return 0;\n const tLo = data[hi].time, tHi = data[lo].time;\n const frac = tHi !== tLo ? (timestamp - tLo) / (tHi - tLo) : 0;\n return hi + frac;\n}\n\n/**\n * Resolve an anchor `time` value to a (possibly fractional) bar index in the\n * current series. When `viewport.data` is set, `time` is interpreted as a real\n * timestamp and converted via `timestampToBarIndex`. Otherwise `time` is\n * already a bar index and is returned unchanged.\n */\nexport function resolveBarIndex(time: number, viewport: ViewportState): number {\n const data = viewport.data;\n if (data && data.length > 0) {\n return timestampToBarIndex(time, data);\n }\n return time;\n}\n\n/**\n * Map an anchor `time` value to its pixel x. Works whether `time` is a\n * timestamp (when `viewport.data` is set) or a bar index (legacy callers).\n */\nexport function timeToX(time: number, viewport: ViewportState): number {\n return barIndexToX(resolveBarIndex(time, viewport), viewport);\n}\n\n/**\n * Map a pixel x back to an anchor `time` value. Returns a real timestamp when\n * `viewport.data` is set (so the value survives timeframe switches), otherwise\n * returns a bar index for legacy callers.\n */\nexport function xToTime(x: number, viewport: ViewportState): number {\n const idx = xToBarIndex(x, viewport);\n const data = viewport.data;\n if (data && data.length > 0) {\n // Past either end (the empty future, or before the oldest bar) the time\n // is extrapolated, so drawings can be placed there.\n return barIndexToTime(idx, data);\n }\n return idx;\n}\n","/**\n * Drawing on whole device pixels. The chart draws in CSS pixels under the\n * device-pixel-ratio transform, so a 1 px line at a fractional position\n * spreads over two device pixels at half strength and looks soft and thick.\n * Bars drawn here go back to the canvas's own pixels and round to them: a\n * wick is one sharp column, a body has hard edges, at any ratio (1, 1.25, 2…).\n */\n\n/**\n * Rounding to a device pixel turns up from a hair under the half. Bar steps\n * are often round numbers (5.1 px, say) that put bars exactly on half a\n * pixel, where 64-bit arithmetic here and 32-bit on the GPU would round some\n * of them apart; a hair under, both land on the same side. The shaders use\n * the same constant.\n */\nexport const PIXEL_ROUNDING = 0.5037;\n\n/** The device pixel a device-pixel position rounds to. */\nexport function toPixel(v: number): number {\n return Math.floor(v + PIXEL_ROUNDING);\n}\n\nfunction transformOf(ctx: CanvasRenderingContext2D): { a: number; d: number; e: number; f: number } {\n const m = typeof ctx.getTransform === 'function' ? ctx.getTransform() : undefined;\n return {\n a: m && Number.isFinite(m.a) && m.a > 0 ? m.a : 1,\n d: m && Number.isFinite(m.d) && m.d > 0 ? m.d : 1,\n e: m && Number.isFinite(m.e) ? m.e : 0,\n f: m && Number.isFinite(m.f) ? m.f : 0,\n };\n}\n\n/** CSS to device-pixel mapping, rounded to whole pixels. */\nexport interface PixelGrid {\n /** Device pixels per CSS pixel. */\n ratio: number;\n /** The device pixel a CSS x falls on. */\n x(cssX: number): number;\n /** The device pixel a CSS y falls on. */\n y(cssY: number): number;\n /**\n * Left edge (device px) of a column `width` device pixels wide centred on\n * CSS x `cssCenter`: the same column `crispX` strokes for a line there.\n */\n left(cssCenter: number, width: number): number;\n}\n\n/**\n * Run `draw` with the transform reset to device pixels, then put it back.\n * A context without a readable transform (a test stand-in) is taken as 1:1.\n */\nexport function inDevicePixels<T>(ctx: CanvasRenderingContext2D, draw: (grid: PixelGrid) => T): T {\n const { a, d, e, f } = transformOf(ctx);\n ctx.save();\n ctx.setTransform(1, 0, 0, 1, 0, 0);\n try {\n return draw({\n ratio: a,\n x: (v) => toPixel(v * a + e),\n y: (v) => toPixel(v * d + f),\n left: (v, width) => toPixel(v * a + e - width / 2),\n });\n } finally {\n ctx.restore();\n }\n}\n\n/**\n * A bar's columns in device pixels: the wick one CSS pixel wide (at least one\n * device pixel), the body about the bar's width, with an even difference so\n * the wick sits exactly in the middle.\n */\nexport function barColumns(barWidth: number, ratio: number): { body: number; wick: number } {\n const wick = Math.max(1, Math.floor(ratio));\n let body = Math.max(wick, Math.round(barWidth * ratio));\n if ((body - wick) % 2 !== 0) body -= 1;\n return { body: Math.max(body, wick), wick };\n}\n\n/** Snap a line's centre (in CSS px) so a `width`-wide stroke covers whole device pixels. */\nfunction snap(v: number, width: number, scale: number, shift: number): { at: number; width: number } {\n const w = Math.max(1, Math.round(width * scale));\n const half = w % 2 ? 0.5 : 0;\n return { at: (toPixel(v * scale + shift - half) + half - shift) / scale, width: w / scale };\n}\n\n/**\n * A horizontal line's y and width, snapped so the stroke covers whole device\n * pixels: one sharp row instead of a soft two-pixel smear.\n */\nexport function crispY(ctx: CanvasRenderingContext2D, y: number, width: number): { y: number; width: number } {\n const t = transformOf(ctx);\n const s = snap(y, width, t.d, t.f);\n return { y: s.at, width: s.width };\n}\n\n/** A vertical line's x and width, snapped like `crispY`. */\nexport function crispX(ctx: CanvasRenderingContext2D, x: number, width: number): { x: number; width: number } {\n const t = transformOf(ctx);\n const s = snap(x, width, t.a, t.e);\n return { x: s.at, width: s.width };\n}\n","import type { DataSeries, ViewportState } from '@tradecanvas/commons';\nimport { priceToYMapper } from '../viewport/ScaleMapping.js';\nimport { inDevicePixels } from './pixelGrid.js';\n\n/**\n * Below this bar width (CSS px) bar-shaped charts draw one column per pixel\n * instead of one shape per bar: thousands of sub-pixel candles would blur\n * into each other and cost a path segment each.\n */\nexport const DENSE_BAR_WIDTH = 1;\n\nexport function isDense(viewport: Pick<ViewportState, 'barWidth'>): boolean {\n return viewport.barWidth < DENSE_BAR_WIDTH;\n}\n\n/** The bars on one pixel column merged into one: first open, last close, extremes, largest volume. */\nexport interface PixelColumn {\n x: number;\n open: number;\n high: number;\n low: number;\n close: number;\n volume: number;\n}\n\n/**\n * Walk bars `from`..`to` merged per pixel column (`Math.floor` of their x).\n * The column object is reused between calls: copy it to keep it.\n */\nexport function forEachPixelColumn(\n data: DataSeries,\n from: number,\n to: number,\n toX: (index: number) => number,\n visit: (column: Readonly<PixelColumn>) => void,\n): void {\n const last = Math.min(to, data.length - 1);\n if (from > last) return;\n const col: PixelColumn = { x: 0, open: 0, high: 0, low: 0, close: 0, volume: 0 };\n let open = false;\n for (let i = Math.max(0, from); i <= last; i++) {\n const bar = data[i];\n const x = Math.floor(toX(i));\n if (open && x !== col.x) {\n visit(col);\n open = false;\n }\n if (!open) {\n col.x = x;\n col.open = bar.open;\n col.high = bar.high;\n col.low = bar.low;\n col.volume = bar.volume;\n open = true;\n } else {\n if (bar.high > col.high) col.high = bar.high;\n if (bar.low < col.low) col.low = bar.low;\n if (bar.volume > col.volume) col.volume = bar.volume;\n }\n col.close = bar.close;\n }\n if (open) visit(col);\n}\n\n/**\n * Draw a dense price series as one high–low line per pixel column, coloured by\n * the column's direction (its last close against its first open).\n */\nexport function renderDenseBars(\n ctx: CanvasRenderingContext2D,\n data: DataSeries,\n viewport: ViewportState,\n upColor: string,\n downColor: string,\n): void {\n const { from, to } = viewport.visibleRange;\n const barUnit = viewport.barWidth + viewport.barSpacing;\n const offsetX = -viewport.offset + viewport.chartRect.x + viewport.barWidth / 2;\n const toY = priceToYMapper(viewport);\n inDevicePixels(ctx, (px) => {\n const up = new Path2D();\n const down = new Path2D();\n forEachPixelColumn(data, from, to, (i) => i * barUnit + offsetX, (c) => {\n const top = px.y(toY(c.high));\n const bottom = px.y(toY(c.low));\n // A flat column still gets a pixel, like a doji's body.\n // Each column reaches the next with no gap: at 125% a CSS pixel is 1 or 2 device pixels.\n const left = px.x(c.x);\n const width = Math.max(1, px.x(c.x + 1) - left);\n (c.close >= c.open ? up : down).rect(left, Math.min(top, bottom), width, Math.max(Math.abs(bottom - top), 1));\n });\n ctx.fillStyle = upColor;\n ctx.fill(up);\n ctx.fillStyle = downColor;\n ctx.fill(down);\n });\n}\n","import type { ViewportState } from '@tradecanvas/commons';\nimport { computeTickStep } from '@tradecanvas/commons';\nimport { priceToYMapper } from '../viewport/ScaleMapping.js';\n\n/** The grid's lines as CSS-pixel centres: one across per price step, one down every few slots. */\nexport interface GridLines {\n horizontal: number[];\n vertical: number[];\n}\n\n/**\n * Where the axes put their labels: the grid draws its lines there, so lines\n * and labels agree. Either can be left out for the grid's own even spacing.\n */\nexport interface GridMarks {\n /** Prices the price axis labels. */\n prices?: readonly number[];\n /** Slots the time axis labels. */\n slots?: readonly number[];\n}\n\n/** Bars between vertical lines: at least this many pixels apart. */\nconst MIN_COLUMN_SPACING = 80;\n\n/** Where the grid lines go, for the 2D grid and the GPU alike. */\nexport function gridLines(viewport: ViewportState, marks: GridMarks = {}): GridLines {\n const { chartRect, priceRange } = viewport;\n if (priceRange.max - priceRange.min <= 0) return { horizontal: [], vertical: [] };\n const toY = priceToYMapper(viewport);\n\n const horizontal: number[] = [];\n if (marks.prices) {\n for (const price of marks.prices) horizontal.push(Math.round(toY(price)) + 0.5);\n } else {\n const priceStep = computeTickStep(priceRange.min, priceRange.max, 8);\n const firstPrice = Math.ceil(priceRange.min / priceStep) * priceStep;\n for (let i = 0; firstPrice + i * priceStep <= priceRange.max; i++) {\n horizontal.push(Math.round(toY(firstPrice + i * priceStep)) + 0.5);\n }\n }\n\n const vertical: number[] = [];\n const barUnit = viewport.barWidth + viewport.barSpacing;\n const offsetX = -viewport.offset + chartRect.x + viewport.barWidth / 2;\n if (marks.slots) {\n for (const slot of marks.slots) vertical.push(Math.round(slot * barUnit + offsetX) + 0.5);\n return { horizontal, vertical };\n }\n const barsPerGrid = Math.max(1, Math.ceil(MIN_COLUMN_SPACING / barUnit));\n // Every slot on screen — the empty space past either end of the data\n // (where the chart can be panned) keeps its grid too.\n const from = Math.floor(viewport.offset / barUnit);\n const to = Math.ceil((viewport.offset + chartRect.width) / barUnit);\n for (let i = from; i <= to; i++) {\n if (i % barsPerGrid !== 0) continue;\n vertical.push(Math.round(i * barUnit + offsetX) + 0.5);\n }\n return { horizontal, vertical };\n}\n","import type { ViewportState, Theme, ResolvedLineLook } from '@tradecanvas/commons';\nimport { lineDash } from '@tradecanvas/commons';\nimport { gridLines, type GridMarks } from './gridLines.js';\n\n/** The grid's dashes, as its lines are drawn when `dashed`. */\nconst GRID_DASH = [4, 4];\n\nexport class GridRenderer {\n private visible = true;\n\n setVisible(v: boolean): void { this.visible = v; }\n isVisible(): boolean { return this.visible; }\n\n /** `marks`: where the axes put their labels, for the lines to agree with them. */\n render(ctx: CanvasRenderingContext2D, viewport: ViewportState, theme: Theme, marks?: GridMarks): void {\n if (!this.visible) return;\n const { chartRect } = viewport;\n const { horizontal, vertical } = gridLines(viewport, marks);\n const looks = gridLooks(theme);\n const h = looks.horizontal;\n const v = looks.vertical;\n // Both ways alike: one path, so a see-through colour isn't laid twice where they cross.\n if (h.visible && v.visible && h.color === v.color && h.style === v.style && h.width === v.width) {\n stroke(ctx, h, () => {\n for (const y of horizontal) {\n const at = onPixel(y, h.width);\n ctx.moveTo(chartRect.x, at);\n ctx.lineTo(chartRect.x + chartRect.width, at);\n }\n for (const x of vertical) {\n const at = onPixel(x, v.width);\n ctx.moveTo(at, chartRect.y);\n ctx.lineTo(at, chartRect.y + chartRect.height);\n }\n });\n ctx.setLineDash([]);\n return;\n }\n if (looks.horizontal.visible && horizontal.length > 0) {\n stroke(ctx, looks.horizontal, () => {\n for (const y of horizontal) {\n const at = onPixel(y, looks.horizontal.width);\n ctx.moveTo(chartRect.x, at);\n ctx.lineTo(chartRect.x + chartRect.width, at);\n }\n });\n }\n if (looks.vertical.visible && vertical.length > 0) {\n stroke(ctx, looks.vertical, () => {\n for (const x of vertical) {\n const at = onPixel(x, looks.vertical.width);\n ctx.moveTo(at, chartRect.y);\n ctx.lineTo(at, chartRect.y + chartRect.height);\n }\n });\n }\n ctx.setLineDash([]);\n }\n}\n\n/** The grid's looks each way: the resolved style's, or the theme's grid colour, solid, 1 px. */\nexport function gridLooks(theme: Theme): { horizontal: ResolvedLineLook; vertical: ResolvedLineLook } {\n const plain: ResolvedLineLook = { visible: true, color: theme.grid, style: 'solid', width: 1 };\n return theme.style?.grid ?? { horizontal: plain, vertical: plain };\n}\n\n/**\n * Whether the GPU can draw the grid as it looks: every way shown is solid,\n * 1 px, and they share a colour. Otherwise the grid goes on Canvas 2D.\n */\nexport function gridFitsGpu(theme: Theme): boolean {\n const { horizontal, vertical } = gridLooks(theme);\n const shown = [horizontal, vertical].filter((look) => look.visible);\n return shown.every((look) => look.style === 'solid' && look.width === 1 && look.color === shown[0].color);\n}\n\n/** One path per way: a single stroke call for all its lines. */\nfunction stroke(ctx: CanvasRenderingContext2D, look: ResolvedLineLook, path: () => void): void {\n ctx.strokeStyle = look.color;\n ctx.lineWidth = look.width;\n ctx.setLineDash(lineDash(look.style, GRID_DASH, look.width));\n ctx.beginPath();\n path();\n ctx.stroke();\n}\n\n/** Grid lines come on the half pixel (crisp at 1 px); an even width is crisp on the whole pixel. */\nfunction onPixel(at: number, width: number): number {\n return width % 2 === 0 ? Math.round(at) : at;\n}\n","/**\n * The WebGL contexts the charts on a page hold at once. Chrome and Safari\n * keep about 16 a page and, past that, drop the oldest, whoever's it is (a\n * live chart's, a map's), never to hand it back. The charts stop short of\n * that and leave the rest to the page; a chart asked for WebGL past the limit\n * draws with Canvas 2D until a context is let go. The count is per copy of\n * the library loaded on the page.\n */\n\n/** How many charts draw with WebGL at once, unless set otherwise. */\nexport const DEFAULT_MAX_WEBGL_CHARTS = 8;\n\nlet limit = DEFAULT_MAX_WEBGL_CHARTS;\nlet held = 0;\nconst waiting = new Set<() => void>();\n\n/**\n * At most `count` charts on the page draw with WebGL at once (default 8;\n * `Infinity` for no limit). Charts that draw with WebGL already keep it when\n * the limit drops below them; it holds for those asking from then on.\n */\nexport function setMaxWebGLCharts(count: number): void {\n limit = Number.isNaN(count) ? DEFAULT_MAX_WEBGL_CHARTS : Math.max(0, Math.floor(count));\n if (gpuContextsLeft() > 0) wakeWaiting();\n}\n\n/** How many more charts may draw with WebGL now. */\nexport function gpuContextsLeft(): number {\n return Math.max(0, limit - held);\n}\n\n/** A context of the charts' share, or null when they hold all of it: the function given back lets it go (once). */\nexport function claimGpuContext(): (() => void) | null {\n if (held >= limit) return null;\n held++;\n let released = false;\n return () => {\n if (released) return;\n released = true;\n held--;\n wakeWaiting();\n };\n}\n\n/** `callback`, once, the next time a context may be had; the function given back stops waiting. */\nexport function whenGpuContextFree(callback: () => void): () => void {\n waiting.add(callback);\n return () => {\n waiting.delete(callback);\n };\n}\n\nfunction wakeWaiting(): void {\n const callbacks = [...waiting];\n waiting.clear();\n for (const callback of callbacks) {\n try {\n callback();\n } catch (err) {\n // One that throws stops none of the others; its error still shows.\n queueMicrotask(() => {\n throw err;\n });\n }\n }\n}\n"],"mappings":"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"}
|
|
@@ -214,19 +214,31 @@ function j(e, t, n, r, i) {
|
|
|
214
214
|
//#endregion
|
|
215
215
|
//#region src/axis/gridLines.ts
|
|
216
216
|
var M = 80;
|
|
217
|
-
function N(e) {
|
|
218
|
-
let { chartRect:
|
|
219
|
-
if (
|
|
217
|
+
function N(e, n = {}) {
|
|
218
|
+
let { chartRect: r, priceRange: i } = e;
|
|
219
|
+
if (i.max - i.min <= 0) return {
|
|
220
220
|
horizontal: [],
|
|
221
221
|
vertical: []
|
|
222
222
|
};
|
|
223
|
-
let
|
|
224
|
-
for (let e
|
|
225
|
-
|
|
226
|
-
|
|
223
|
+
let o = a(e), s = [];
|
|
224
|
+
if (n.prices) for (let e of n.prices) s.push(Math.round(o(e)) + .5);
|
|
225
|
+
else {
|
|
226
|
+
let e = t(i.min, i.max, 8), n = Math.ceil(i.min / e) * e;
|
|
227
|
+
for (let t = 0; n + t * e <= i.max; t++) s.push(Math.round(o(n + t * e)) + .5);
|
|
228
|
+
}
|
|
229
|
+
let c = [], l = e.barWidth + e.barSpacing, u = -e.offset + r.x + e.barWidth / 2;
|
|
230
|
+
if (n.slots) {
|
|
231
|
+
for (let e of n.slots) c.push(Math.round(e * l + u) + .5);
|
|
232
|
+
return {
|
|
233
|
+
horizontal: s,
|
|
234
|
+
vertical: c
|
|
235
|
+
};
|
|
236
|
+
}
|
|
237
|
+
let d = Math.max(1, Math.ceil(M / l)), f = Math.floor(e.offset / l), p = Math.ceil((e.offset + r.width) / l);
|
|
238
|
+
for (let e = f; e <= p; e++) e % d === 0 && c.push(Math.round(e * l + u) + .5);
|
|
227
239
|
return {
|
|
228
|
-
horizontal:
|
|
229
|
-
vertical:
|
|
240
|
+
horizontal: s,
|
|
241
|
+
vertical: c
|
|
230
242
|
};
|
|
231
243
|
}
|
|
232
244
|
//#endregion
|
|
@@ -239,31 +251,31 @@ var P = [4, 4], F = class {
|
|
|
239
251
|
isVisible() {
|
|
240
252
|
return this.visible;
|
|
241
253
|
}
|
|
242
|
-
render(e, t, n) {
|
|
254
|
+
render(e, t, n, r) {
|
|
243
255
|
if (!this.visible) return;
|
|
244
|
-
let { chartRect:
|
|
245
|
-
if (
|
|
246
|
-
R(e,
|
|
247
|
-
for (let t of i) {
|
|
248
|
-
let n = z(t, s.width);
|
|
249
|
-
e.moveTo(r.x, n), e.lineTo(r.x + r.width, n);
|
|
250
|
-
}
|
|
256
|
+
let { chartRect: i } = t, { horizontal: a, vertical: o } = N(t, r), s = I(n), c = s.horizontal, l = s.vertical;
|
|
257
|
+
if (c.visible && l.visible && c.color === l.color && c.style === l.style && c.width === l.width) {
|
|
258
|
+
R(e, c, () => {
|
|
251
259
|
for (let t of a) {
|
|
252
260
|
let n = z(t, c.width);
|
|
253
|
-
e.moveTo(
|
|
261
|
+
e.moveTo(i.x, n), e.lineTo(i.x + i.width, n);
|
|
262
|
+
}
|
|
263
|
+
for (let t of o) {
|
|
264
|
+
let n = z(t, l.width);
|
|
265
|
+
e.moveTo(n, i.y), e.lineTo(n, i.y + i.height);
|
|
254
266
|
}
|
|
255
267
|
}), e.setLineDash([]);
|
|
256
268
|
return;
|
|
257
269
|
}
|
|
258
|
-
|
|
259
|
-
for (let t of i) {
|
|
260
|
-
let n = z(t, o.horizontal.width);
|
|
261
|
-
e.moveTo(r.x, n), e.lineTo(r.x + r.width, n);
|
|
262
|
-
}
|
|
263
|
-
}), o.vertical.visible && a.length > 0 && R(e, o.vertical, () => {
|
|
270
|
+
s.horizontal.visible && a.length > 0 && R(e, s.horizontal, () => {
|
|
264
271
|
for (let t of a) {
|
|
265
|
-
let n = z(t,
|
|
266
|
-
e.moveTo(
|
|
272
|
+
let n = z(t, s.horizontal.width);
|
|
273
|
+
e.moveTo(i.x, n), e.lineTo(i.x + i.width, n);
|
|
274
|
+
}
|
|
275
|
+
}), s.vertical.visible && o.length > 0 && R(e, s.vertical, () => {
|
|
276
|
+
for (let t of o) {
|
|
277
|
+
let n = z(t, s.vertical.width);
|
|
278
|
+
e.moveTo(n, i.y), e.lineTo(n, i.y + i.height);
|
|
267
279
|
}
|
|
268
280
|
}), e.setLineDash([]);
|
|
269
281
|
}
|
|
@@ -326,4 +338,4 @@ function J() {
|
|
|
326
338
|
//#endregion
|
|
327
339
|
export { s as A, p as C, _ as D, a as E, c as M, v as O, m as S, i as T, E as _, q as a, r as b, I as c, A as d, k as f, D as g, w as h, W as i, y as j, g as k, N as l, b as m, K as n, F as o, j as p, G as r, L as s, B as t, O as u, C as v, o as w, u as x, h as y };
|
|
328
340
|
|
|
329
|
-
//# sourceMappingURL=gpuContexts-
|
|
341
|
+
//# sourceMappingURL=gpuContexts-BXj2qguo.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"gpuContexts-BXj2qguo.js","names":[],"sources":["../src/viewport/ScaleMapping.ts","../src/charts/pixelGrid.ts","../src/charts/denseBars.ts","../src/axis/gridLines.ts","../src/axis/GridRenderer.ts","../src/engine/gpuContexts.ts"],"sourcesContent":["import type { ViewportState } from '@tradecanvas/commons';\nimport { barTimeUnit } from '@tradecanvas/commons';\n\nexport function barIndexToX(index: number, viewport: ViewportState): number {\n const barUnit = viewport.barWidth + viewport.barSpacing;\n return index * barUnit - viewport.offset + viewport.chartRect.x + viewport.barWidth / 2;\n}\n\nexport function priceToY(price: number, viewport: ViewportState): number {\n const { min, max } = viewport.priceRange;\n const { y: top, height } = viewport.chartRect;\n let ratio: number;\n if (viewport.logScale && min > 0 && max > 0) {\n const logMin = Math.log(min);\n const logRange = Math.log(max) - logMin;\n if (logRange === 0) return top + height / 2;\n ratio = (Math.log(Math.max(price, Number.EPSILON)) - logMin) / logRange;\n } else {\n const range = max - min;\n if (range === 0) return top + height / 2;\n ratio = (price - min) / range;\n }\n return top + height * (viewport.invertScale ? ratio : 1 - ratio);\n}\n\n/**\n * `priceToY` for one frame, with the per-call work hoisted out: for renderers\n * that map every visible bar. Follows the log scale and the inverted scale.\n */\nexport function priceToYMapper(viewport: ViewportState): (price: number) => number {\n const { min, max } = viewport.priceRange;\n const { y: top, height } = viewport.chartRect;\n const invert = viewport.invertScale === true;\n if (viewport.logScale && min > 0 && max > 0) {\n const logMin = Math.log(min);\n const logRange = Math.log(max) - logMin;\n if (logRange === 0) return () => top + height / 2;\n const k = height / logRange;\n const bottom = top + height;\n return invert\n ? (price) => top + (Math.log(Math.max(price, Number.EPSILON)) - logMin) * k\n : (price) => bottom - (Math.log(Math.max(price, Number.EPSILON)) - logMin) * k;\n }\n const range = max - min;\n if (range === 0) return () => top + height / 2;\n const k = height / range;\n return invert ? (price) => top + (price - min) * k : (price) => top + (max - price) * k;\n}\n\n/**\n * Where bucket `b` of `count` equal price buckets across the price range sits\n * on screen (bucket 0 holds the lowest prices), on any scale. `toY` is the\n * frame's `priceToYMapper`.\n */\nexport function priceBucketRow(\n b: number,\n count: number,\n viewport: ViewportState,\n toY: (price: number) => number,\n): { top: number; height: number; mid: number } {\n const { min, max } = viewport.priceRange;\n const step = (max - min) / count;\n const yLow = toY(min + b * step);\n const yHigh = toY(min + (b + 1) * step);\n return { top: Math.min(yLow, yHigh), height: Math.abs(yLow - yHigh), mid: (yLow + yHigh) / 2 };\n}\n\nexport function xToBarIndex(x: number, viewport: ViewportState): number {\n const barUnit = viewport.barWidth + viewport.barSpacing;\n return Math.round((x - viewport.chartRect.x - viewport.barWidth / 2 + viewport.offset) / barUnit);\n}\n\nexport function yToPrice(y: number, viewport: ViewportState): number {\n const { min, max } = viewport.priceRange;\n const fromTop = (y - viewport.chartRect.y) / viewport.chartRect.height;\n const ratio = viewport.invertScale ? fromTop : 1 - fromTop;\n if (viewport.logScale && min > 0 && max > 0) {\n const logMin = Math.log(min);\n const logMax = Math.log(max);\n return Math.exp(logMin + (logMax - logMin) * ratio);\n }\n return min + (max - min) * ratio;\n}\n\ntype TimedSeries = ReadonlyArray<{ time: number }>;\n\nconst stepCache = new WeakMap<TimedSeries, { length: number; step: number }>();\n\n/**\n * Typical spacing between bar times — the median of the last ~20 intervals,\n * so a weekend or halt gap doesn't skew it. Used to place times beyond either\n * end of the data (the empty future the chart can be panned into). Cached per\n * series and length; 0 when there are fewer than two bars.\n */\nexport function barTimeStep(data: TimedSeries): number {\n const n = data.length;\n if (n < 2) return 0;\n const cached = stepCache.get(data);\n if (cached && cached.length === n) return cached.step;\n const diffs: number[] = [];\n for (let i = Math.max(1, n - 20); i < n; i++) diffs.push(data[i].time - data[i - 1].time);\n diffs.sort((a, b) => a - b);\n const step = Math.max(0, diffs[diffs.length >> 1]);\n stepCache.set(data, { length: n, step });\n return step;\n}\n\n/** Bars the spacing before the oldest bar is averaged over. */\nconst PAST_STEP_SAMPLE = 100;\n\nconst pastStepCache = new WeakMap<TimedSeries, { length: number; first: number; end: number; step: number }>();\n\n/**\n * The average spacing of the first bars, weekends, nights and halts\n * included: how far back in time a slot before the oldest bar goes, so an\n * extrapolated date lands about where the bars, once loaded, would put it.\n * Cached per series; `barTimeStep` when the first bars share one time, 0\n * when there are fewer than two bars.\n */\nexport function pastTimeStep(data: TimedSeries): number {\n const n = data.length;\n if (n < 2) return 0;\n const k = Math.min(n - 1, PAST_STEP_SAMPLE);\n const cached = pastStepCache.get(data);\n if (cached && cached.length === n && cached.first === data[0].time && cached.end === data[k].time) return cached.step;\n const average = (data[k].time - data[0].time) / k;\n const step = average > 0 ? average : barTimeStep(data);\n pastStepCache.set(data, { length: n, first: data[0].time, end: data[k].time, step });\n return step;\n}\n\n/** `barTimeStep` in milliseconds whatever unit the series uses (`barTimeUnit`). */\nexport function barTimeStepMs(data: TimedSeries): number {\n return barTimeStep(data) * barTimeUnit(data);\n}\n\n/**\n * Time at bar index `index`, extrapolated past either end of the data: by\n * `barTimeStep` into the future right of the newest bar, by `pastTimeStep`\n * before the oldest.\n */\nexport function barIndexToTime(index: number, data: TimedSeries): number {\n const n = data.length;\n if (n === 0) return index;\n const last = n - 1;\n if (index > last) return data[last].time + (index - last) * barTimeStep(data);\n if (index < 0) return data[0].time + index * pastTimeStep(data);\n const lo = Math.floor(index);\n if (lo === index || lo >= last) return data[lo].time;\n return data[lo].time + (index - lo) * (data[lo + 1].time - data[lo].time);\n}\n\n/**\n * Convert a bar timestamp to its data-array index via binary search.\n * Falls back to fractional interpolation when the timestamp falls between bars,\n * and extrapolates (as `barIndexToTime` does) for times beyond either end — so a drawing\n * anchored in the future keeps its place instead of collapsing onto the last bar.\n * Returns -1 if data is empty.\n */\nexport function timestampToBarIndex(timestamp: number, data: TimedSeries): number {\n if (data.length === 0) return -1;\n const first = data[0].time;\n const lastIdx = data.length - 1;\n const lastTime = data[lastIdx].time;\n if (timestamp <= first || timestamp >= lastTime) {\n if (timestamp === first) return 0;\n if (timestamp === lastTime) return lastIdx;\n const step = timestamp < first ? pastTimeStep(data) : barTimeStep(data);\n if (step <= 0) return timestamp < first ? 0 : lastIdx;\n return timestamp < first ? (timestamp - first) / step : lastIdx + (timestamp - lastTime) / step;\n }\n // Binary search\n let lo = 0, hi = data.length - 1;\n while (lo <= hi) {\n const mid = (lo + hi) >>> 1;\n if (data[mid].time === timestamp) return mid;\n if (data[mid].time < timestamp) lo = mid + 1;\n else hi = mid - 1;\n }\n // lo is the insertion point; interpolate between hi and lo\n if (lo >= data.length) return data.length - 1;\n if (hi < 0) return 0;\n const tLo = data[hi].time, tHi = data[lo].time;\n const frac = tHi !== tLo ? (timestamp - tLo) / (tHi - tLo) : 0;\n return hi + frac;\n}\n\n/**\n * Resolve an anchor `time` value to a (possibly fractional) bar index in the\n * current series. When `viewport.data` is set, `time` is interpreted as a real\n * timestamp and converted via `timestampToBarIndex`. Otherwise `time` is\n * already a bar index and is returned unchanged.\n */\nexport function resolveBarIndex(time: number, viewport: ViewportState): number {\n const data = viewport.data;\n if (data && data.length > 0) {\n return timestampToBarIndex(time, data);\n }\n return time;\n}\n\n/**\n * Map an anchor `time` value to its pixel x. Works whether `time` is a\n * timestamp (when `viewport.data` is set) or a bar index (legacy callers).\n */\nexport function timeToX(time: number, viewport: ViewportState): number {\n return barIndexToX(resolveBarIndex(time, viewport), viewport);\n}\n\n/**\n * Map a pixel x back to an anchor `time` value. Returns a real timestamp when\n * `viewport.data` is set (so the value survives timeframe switches), otherwise\n * returns a bar index for legacy callers.\n */\nexport function xToTime(x: number, viewport: ViewportState): number {\n const idx = xToBarIndex(x, viewport);\n const data = viewport.data;\n if (data && data.length > 0) {\n // Past either end (the empty future, or before the oldest bar) the time\n // is extrapolated, so drawings can be placed there.\n return barIndexToTime(idx, data);\n }\n return idx;\n}\n","/**\n * Drawing on whole device pixels. The chart draws in CSS pixels under the\n * device-pixel-ratio transform, so a 1 px line at a fractional position\n * spreads over two device pixels at half strength and looks soft and thick.\n * Bars drawn here go back to the canvas's own pixels and round to them: a\n * wick is one sharp column, a body has hard edges, at any ratio (1, 1.25, 2…).\n */\n\n/**\n * Rounding to a device pixel turns up from a hair under the half. Bar steps\n * are often round numbers (5.1 px, say) that put bars exactly on half a\n * pixel, where 64-bit arithmetic here and 32-bit on the GPU would round some\n * of them apart; a hair under, both land on the same side. The shaders use\n * the same constant.\n */\nexport const PIXEL_ROUNDING = 0.5037;\n\n/** The device pixel a device-pixel position rounds to. */\nexport function toPixel(v: number): number {\n return Math.floor(v + PIXEL_ROUNDING);\n}\n\nfunction transformOf(ctx: CanvasRenderingContext2D): { a: number; d: number; e: number; f: number } {\n const m = typeof ctx.getTransform === 'function' ? ctx.getTransform() : undefined;\n return {\n a: m && Number.isFinite(m.a) && m.a > 0 ? m.a : 1,\n d: m && Number.isFinite(m.d) && m.d > 0 ? m.d : 1,\n e: m && Number.isFinite(m.e) ? m.e : 0,\n f: m && Number.isFinite(m.f) ? m.f : 0,\n };\n}\n\n/** CSS to device-pixel mapping, rounded to whole pixels. */\nexport interface PixelGrid {\n /** Device pixels per CSS pixel. */\n ratio: number;\n /** The device pixel a CSS x falls on. */\n x(cssX: number): number;\n /** The device pixel a CSS y falls on. */\n y(cssY: number): number;\n /**\n * Left edge (device px) of a column `width` device pixels wide centred on\n * CSS x `cssCenter`: the same column `crispX` strokes for a line there.\n */\n left(cssCenter: number, width: number): number;\n}\n\n/**\n * Run `draw` with the transform reset to device pixels, then put it back.\n * A context without a readable transform (a test stand-in) is taken as 1:1.\n */\nexport function inDevicePixels<T>(ctx: CanvasRenderingContext2D, draw: (grid: PixelGrid) => T): T {\n const { a, d, e, f } = transformOf(ctx);\n ctx.save();\n ctx.setTransform(1, 0, 0, 1, 0, 0);\n try {\n return draw({\n ratio: a,\n x: (v) => toPixel(v * a + e),\n y: (v) => toPixel(v * d + f),\n left: (v, width) => toPixel(v * a + e - width / 2),\n });\n } finally {\n ctx.restore();\n }\n}\n\n/**\n * A bar's columns in device pixels: the wick one CSS pixel wide (at least one\n * device pixel), the body about the bar's width, with an even difference so\n * the wick sits exactly in the middle.\n */\nexport function barColumns(barWidth: number, ratio: number): { body: number; wick: number } {\n const wick = Math.max(1, Math.floor(ratio));\n let body = Math.max(wick, Math.round(barWidth * ratio));\n if ((body - wick) % 2 !== 0) body -= 1;\n return { body: Math.max(body, wick), wick };\n}\n\n/** Snap a line's centre (in CSS px) so a `width`-wide stroke covers whole device pixels. */\nfunction snap(v: number, width: number, scale: number, shift: number): { at: number; width: number } {\n const w = Math.max(1, Math.round(width * scale));\n const half = w % 2 ? 0.5 : 0;\n return { at: (toPixel(v * scale + shift - half) + half - shift) / scale, width: w / scale };\n}\n\n/**\n * A horizontal line's y and width, snapped so the stroke covers whole device\n * pixels: one sharp row instead of a soft two-pixel smear.\n */\nexport function crispY(ctx: CanvasRenderingContext2D, y: number, width: number): { y: number; width: number } {\n const t = transformOf(ctx);\n const s = snap(y, width, t.d, t.f);\n return { y: s.at, width: s.width };\n}\n\n/** A vertical line's x and width, snapped like `crispY`. */\nexport function crispX(ctx: CanvasRenderingContext2D, x: number, width: number): { x: number; width: number } {\n const t = transformOf(ctx);\n const s = snap(x, width, t.a, t.e);\n return { x: s.at, width: s.width };\n}\n","import type { DataSeries, ViewportState } from '@tradecanvas/commons';\nimport { priceToYMapper } from '../viewport/ScaleMapping.js';\nimport { inDevicePixels } from './pixelGrid.js';\n\n/**\n * Below this bar width (CSS px) bar-shaped charts draw one column per pixel\n * instead of one shape per bar: thousands of sub-pixel candles would blur\n * into each other and cost a path segment each.\n */\nexport const DENSE_BAR_WIDTH = 1;\n\nexport function isDense(viewport: Pick<ViewportState, 'barWidth'>): boolean {\n return viewport.barWidth < DENSE_BAR_WIDTH;\n}\n\n/** The bars on one pixel column merged into one: first open, last close, extremes, largest volume. */\nexport interface PixelColumn {\n x: number;\n open: number;\n high: number;\n low: number;\n close: number;\n volume: number;\n}\n\n/**\n * Walk bars `from`..`to` merged per pixel column (`Math.floor` of their x).\n * The column object is reused between calls: copy it to keep it.\n */\nexport function forEachPixelColumn(\n data: DataSeries,\n from: number,\n to: number,\n toX: (index: number) => number,\n visit: (column: Readonly<PixelColumn>) => void,\n): void {\n const last = Math.min(to, data.length - 1);\n if (from > last) return;\n const col: PixelColumn = { x: 0, open: 0, high: 0, low: 0, close: 0, volume: 0 };\n let open = false;\n for (let i = Math.max(0, from); i <= last; i++) {\n const bar = data[i];\n const x = Math.floor(toX(i));\n if (open && x !== col.x) {\n visit(col);\n open = false;\n }\n if (!open) {\n col.x = x;\n col.open = bar.open;\n col.high = bar.high;\n col.low = bar.low;\n col.volume = bar.volume;\n open = true;\n } else {\n if (bar.high > col.high) col.high = bar.high;\n if (bar.low < col.low) col.low = bar.low;\n if (bar.volume > col.volume) col.volume = bar.volume;\n }\n col.close = bar.close;\n }\n if (open) visit(col);\n}\n\n/**\n * Draw a dense price series as one high–low line per pixel column, coloured by\n * the column's direction (its last close against its first open).\n */\nexport function renderDenseBars(\n ctx: CanvasRenderingContext2D,\n data: DataSeries,\n viewport: ViewportState,\n upColor: string,\n downColor: string,\n): void {\n const { from, to } = viewport.visibleRange;\n const barUnit = viewport.barWidth + viewport.barSpacing;\n const offsetX = -viewport.offset + viewport.chartRect.x + viewport.barWidth / 2;\n const toY = priceToYMapper(viewport);\n inDevicePixels(ctx, (px) => {\n const up = new Path2D();\n const down = new Path2D();\n forEachPixelColumn(data, from, to, (i) => i * barUnit + offsetX, (c) => {\n const top = px.y(toY(c.high));\n const bottom = px.y(toY(c.low));\n // A flat column still gets a pixel, like a doji's body.\n // Each column reaches the next with no gap: at 125% a CSS pixel is 1 or 2 device pixels.\n const left = px.x(c.x);\n const width = Math.max(1, px.x(c.x + 1) - left);\n (c.close >= c.open ? up : down).rect(left, Math.min(top, bottom), width, Math.max(Math.abs(bottom - top), 1));\n });\n ctx.fillStyle = upColor;\n ctx.fill(up);\n ctx.fillStyle = downColor;\n ctx.fill(down);\n });\n}\n","import type { ViewportState } from '@tradecanvas/commons';\nimport { computeTickStep } from '@tradecanvas/commons';\nimport { priceToYMapper } from '../viewport/ScaleMapping.js';\n\n/** The grid's lines as CSS-pixel centres: one across per price step, one down every few slots. */\nexport interface GridLines {\n horizontal: number[];\n vertical: number[];\n}\n\n/**\n * Where the axes put their labels: the grid draws its lines there, so lines\n * and labels agree. Either can be left out for the grid's own even spacing.\n */\nexport interface GridMarks {\n /** Prices the price axis labels. */\n prices?: readonly number[];\n /** Slots the time axis labels. */\n slots?: readonly number[];\n}\n\n/** Bars between vertical lines: at least this many pixels apart. */\nconst MIN_COLUMN_SPACING = 80;\n\n/** Where the grid lines go, for the 2D grid and the GPU alike. */\nexport function gridLines(viewport: ViewportState, marks: GridMarks = {}): GridLines {\n const { chartRect, priceRange } = viewport;\n if (priceRange.max - priceRange.min <= 0) return { horizontal: [], vertical: [] };\n const toY = priceToYMapper(viewport);\n\n const horizontal: number[] = [];\n if (marks.prices) {\n for (const price of marks.prices) horizontal.push(Math.round(toY(price)) + 0.5);\n } else {\n const priceStep = computeTickStep(priceRange.min, priceRange.max, 8);\n const firstPrice = Math.ceil(priceRange.min / priceStep) * priceStep;\n for (let i = 0; firstPrice + i * priceStep <= priceRange.max; i++) {\n horizontal.push(Math.round(toY(firstPrice + i * priceStep)) + 0.5);\n }\n }\n\n const vertical: number[] = [];\n const barUnit = viewport.barWidth + viewport.barSpacing;\n const offsetX = -viewport.offset + chartRect.x + viewport.barWidth / 2;\n if (marks.slots) {\n for (const slot of marks.slots) vertical.push(Math.round(slot * barUnit + offsetX) + 0.5);\n return { horizontal, vertical };\n }\n const barsPerGrid = Math.max(1, Math.ceil(MIN_COLUMN_SPACING / barUnit));\n // Every slot on screen — the empty space past either end of the data\n // (where the chart can be panned) keeps its grid too.\n const from = Math.floor(viewport.offset / barUnit);\n const to = Math.ceil((viewport.offset + chartRect.width) / barUnit);\n for (let i = from; i <= to; i++) {\n if (i % barsPerGrid !== 0) continue;\n vertical.push(Math.round(i * barUnit + offsetX) + 0.5);\n }\n return { horizontal, vertical };\n}\n","import type { ViewportState, Theme, ResolvedLineLook } from '@tradecanvas/commons';\nimport { lineDash } from '@tradecanvas/commons';\nimport { gridLines, type GridMarks } from './gridLines.js';\n\n/** The grid's dashes, as its lines are drawn when `dashed`. */\nconst GRID_DASH = [4, 4];\n\nexport class GridRenderer {\n private visible = true;\n\n setVisible(v: boolean): void { this.visible = v; }\n isVisible(): boolean { return this.visible; }\n\n /** `marks`: where the axes put their labels, for the lines to agree with them. */\n render(ctx: CanvasRenderingContext2D, viewport: ViewportState, theme: Theme, marks?: GridMarks): void {\n if (!this.visible) return;\n const { chartRect } = viewport;\n const { horizontal, vertical } = gridLines(viewport, marks);\n const looks = gridLooks(theme);\n const h = looks.horizontal;\n const v = looks.vertical;\n // Both ways alike: one path, so a see-through colour isn't laid twice where they cross.\n if (h.visible && v.visible && h.color === v.color && h.style === v.style && h.width === v.width) {\n stroke(ctx, h, () => {\n for (const y of horizontal) {\n const at = onPixel(y, h.width);\n ctx.moveTo(chartRect.x, at);\n ctx.lineTo(chartRect.x + chartRect.width, at);\n }\n for (const x of vertical) {\n const at = onPixel(x, v.width);\n ctx.moveTo(at, chartRect.y);\n ctx.lineTo(at, chartRect.y + chartRect.height);\n }\n });\n ctx.setLineDash([]);\n return;\n }\n if (looks.horizontal.visible && horizontal.length > 0) {\n stroke(ctx, looks.horizontal, () => {\n for (const y of horizontal) {\n const at = onPixel(y, looks.horizontal.width);\n ctx.moveTo(chartRect.x, at);\n ctx.lineTo(chartRect.x + chartRect.width, at);\n }\n });\n }\n if (looks.vertical.visible && vertical.length > 0) {\n stroke(ctx, looks.vertical, () => {\n for (const x of vertical) {\n const at = onPixel(x, looks.vertical.width);\n ctx.moveTo(at, chartRect.y);\n ctx.lineTo(at, chartRect.y + chartRect.height);\n }\n });\n }\n ctx.setLineDash([]);\n }\n}\n\n/** The grid's looks each way: the resolved style's, or the theme's grid colour, solid, 1 px. */\nexport function gridLooks(theme: Theme): { horizontal: ResolvedLineLook; vertical: ResolvedLineLook } {\n const plain: ResolvedLineLook = { visible: true, color: theme.grid, style: 'solid', width: 1 };\n return theme.style?.grid ?? { horizontal: plain, vertical: plain };\n}\n\n/**\n * Whether the GPU can draw the grid as it looks: every way shown is solid,\n * 1 px, and they share a colour. Otherwise the grid goes on Canvas 2D.\n */\nexport function gridFitsGpu(theme: Theme): boolean {\n const { horizontal, vertical } = gridLooks(theme);\n const shown = [horizontal, vertical].filter((look) => look.visible);\n return shown.every((look) => look.style === 'solid' && look.width === 1 && look.color === shown[0].color);\n}\n\n/** One path per way: a single stroke call for all its lines. */\nfunction stroke(ctx: CanvasRenderingContext2D, look: ResolvedLineLook, path: () => void): void {\n ctx.strokeStyle = look.color;\n ctx.lineWidth = look.width;\n ctx.setLineDash(lineDash(look.style, GRID_DASH, look.width));\n ctx.beginPath();\n path();\n ctx.stroke();\n}\n\n/** Grid lines come on the half pixel (crisp at 1 px); an even width is crisp on the whole pixel. */\nfunction onPixel(at: number, width: number): number {\n return width % 2 === 0 ? Math.round(at) : at;\n}\n","/**\n * The WebGL contexts the charts on a page hold at once. Chrome and Safari\n * keep about 16 a page and, past that, drop the oldest, whoever's it is (a\n * live chart's, a map's), never to hand it back. The charts stop short of\n * that and leave the rest to the page; a chart asked for WebGL past the limit\n * draws with Canvas 2D until a context is let go. The count is per copy of\n * the library loaded on the page.\n */\n\n/** How many charts draw with WebGL at once, unless set otherwise. */\nexport const DEFAULT_MAX_WEBGL_CHARTS = 8;\n\nlet limit = DEFAULT_MAX_WEBGL_CHARTS;\nlet held = 0;\nconst waiting = new Set<() => void>();\n\n/**\n * At most `count` charts on the page draw with WebGL at once (default 8;\n * `Infinity` for no limit). Charts that draw with WebGL already keep it when\n * the limit drops below them; it holds for those asking from then on.\n */\nexport function setMaxWebGLCharts(count: number): void {\n limit = Number.isNaN(count) ? DEFAULT_MAX_WEBGL_CHARTS : Math.max(0, Math.floor(count));\n if (gpuContextsLeft() > 0) wakeWaiting();\n}\n\n/** How many more charts may draw with WebGL now. */\nexport function gpuContextsLeft(): number {\n return Math.max(0, limit - held);\n}\n\n/** A context of the charts' share, or null when they hold all of it: the function given back lets it go (once). */\nexport function claimGpuContext(): (() => void) | null {\n if (held >= limit) return null;\n held++;\n let released = false;\n return () => {\n if (released) return;\n released = true;\n held--;\n wakeWaiting();\n };\n}\n\n/** `callback`, once, the next time a context may be had; the function given back stops waiting. */\nexport function whenGpuContextFree(callback: () => void): () => void {\n waiting.add(callback);\n return () => {\n waiting.delete(callback);\n };\n}\n\nfunction wakeWaiting(): void {\n const callbacks = [...waiting];\n waiting.clear();\n for (const callback of callbacks) {\n try {\n callback();\n } catch (err) {\n // One that throws stops none of the others; its error still shows.\n queueMicrotask(() => {\n throw err;\n });\n }\n }\n}\n"],"mappings":"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"}
|