@tranding-custom-chart/renderer-canvas 0.0.0-stage → 2.0.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/README.md +40 -2
- package/dist/canvas-engine.d.ts +82 -0
- package/dist/canvas-engine.d.ts.map +1 -0
- package/dist/canvas-engine.js +594 -0
- package/dist/dpi.d.ts +31 -0
- package/dist/dpi.d.ts.map +1 -0
- package/dist/dpi.js +65 -0
- package/dist/index.d.ts +38 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +37 -0
- package/dist/renderers/bar-renderer.d.ts +26 -0
- package/dist/renderers/bar-renderer.d.ts.map +1 -0
- package/dist/renderers/bar-renderer.js +45 -0
- package/dist/renderers/baseline-renderer.d.ts +20 -0
- package/dist/renderers/baseline-renderer.d.ts.map +1 -0
- package/dist/renderers/baseline-renderer.js +101 -0
- package/dist/renderers/box-plot-renderer.d.ts +14 -0
- package/dist/renderers/box-plot-renderer.d.ts.map +1 -0
- package/dist/renderers/box-plot-renderer.js +76 -0
- package/dist/renderers/bubble-renderer.d.ts +14 -0
- package/dist/renderers/bubble-renderer.d.ts.map +1 -0
- package/dist/renderers/bubble-renderer.js +37 -0
- package/dist/renderers/candlestick-renderer.d.ts +18 -0
- package/dist/renderers/candlestick-renderer.d.ts.map +1 -0
- package/dist/renderers/candlestick-renderer.js +87 -0
- package/dist/renderers/columns-renderer.d.ts +21 -0
- package/dist/renderers/columns-renderer.d.ts.map +1 -0
- package/dist/renderers/columns-renderer.js +35 -0
- package/dist/renderers/crosshair-renderer.d.ts +19 -0
- package/dist/renderers/crosshair-renderer.d.ts.map +1 -0
- package/dist/renderers/crosshair-renderer.js +71 -0
- package/dist/renderers/curved-line-renderer.d.ts +17 -0
- package/dist/renderers/curved-line-renderer.d.ts.map +1 -0
- package/dist/renderers/curved-line-renderer.js +46 -0
- package/dist/renderers/drawing-renderer.d.ts +19 -0
- package/dist/renderers/drawing-renderer.d.ts.map +1 -0
- package/dist/renderers/drawing-renderer.js +487 -0
- package/dist/renderers/grid-renderer.d.ts +26 -0
- package/dist/renderers/grid-renderer.d.ts.map +1 -0
- package/dist/renderers/grid-renderer.js +103 -0
- package/dist/renderers/heatmap-renderer.d.ts +16 -0
- package/dist/renderers/heatmap-renderer.d.ts.map +1 -0
- package/dist/renderers/heatmap-renderer.js +80 -0
- package/dist/renderers/high-low-renderer.d.ts +19 -0
- package/dist/renderers/high-low-renderer.d.ts.map +1 -0
- package/dist/renderers/high-low-renderer.js +28 -0
- package/dist/renderers/hlc-area-renderer.d.ts +22 -0
- package/dist/renderers/hlc-area-renderer.d.ts.map +1 -0
- package/dist/renderers/hlc-area-renderer.js +72 -0
- package/dist/renderers/hollow-candlestick-renderer.d.ts +26 -0
- package/dist/renderers/hollow-candlestick-renderer.d.ts.map +1 -0
- package/dist/renderers/hollow-candlestick-renderer.js +71 -0
- package/dist/renderers/horizontal-bar-renderer.d.ts +25 -0
- package/dist/renderers/horizontal-bar-renderer.d.ts.map +1 -0
- package/dist/renderers/horizontal-bar-renderer.js +52 -0
- package/dist/renderers/last-price-renderer.d.ts +17 -0
- package/dist/renderers/last-price-renderer.d.ts.map +1 -0
- package/dist/renderers/last-price-renderer.js +46 -0
- package/dist/renderers/line-renderer.d.ts +23 -0
- package/dist/renderers/line-renderer.d.ts.map +1 -0
- package/dist/renderers/line-renderer.js +80 -0
- package/dist/renderers/line-with-markers-renderer.d.ts +13 -0
- package/dist/renderers/line-with-markers-renderer.d.ts.map +1 -0
- package/dist/renderers/line-with-markers-renderer.js +35 -0
- package/dist/renderers/marker-renderer.d.ts +16 -0
- package/dist/renderers/marker-renderer.d.ts.map +1 -0
- package/dist/renderers/marker-renderer.js +91 -0
- package/dist/renderers/mixed-renderer.d.ts +18 -0
- package/dist/renderers/mixed-renderer.d.ts.map +1 -0
- package/dist/renderers/mixed-renderer.js +123 -0
- package/dist/renderers/ohlc-bar-renderer.d.ts +21 -0
- package/dist/renderers/ohlc-bar-renderer.d.ts.map +1 -0
- package/dist/renderers/ohlc-bar-renderer.js +73 -0
- package/dist/renderers/pie-renderer.d.ts +26 -0
- package/dist/renderers/pie-renderer.d.ts.map +1 -0
- package/dist/renderers/pie-renderer.js +71 -0
- package/dist/renderers/polar-area-renderer.d.ts +13 -0
- package/dist/renderers/polar-area-renderer.d.ts.map +1 -0
- package/dist/renderers/polar-area-renderer.js +44 -0
- package/dist/renderers/radar-renderer.d.ts +16 -0
- package/dist/renderers/radar-renderer.d.ts.map +1 -0
- package/dist/renderers/radar-renderer.js +99 -0
- package/dist/renderers/scatter-renderer.d.ts +14 -0
- package/dist/renderers/scatter-renderer.d.ts.map +1 -0
- package/dist/renderers/scatter-renderer.js +42 -0
- package/dist/renderers/stacked-bar-renderer.d.ts +14 -0
- package/dist/renderers/stacked-bar-renderer.d.ts.map +1 -0
- package/dist/renderers/stacked-bar-renderer.js +52 -0
- package/dist/renderers/step-line-renderer.d.ts +19 -0
- package/dist/renderers/step-line-renderer.d.ts.map +1 -0
- package/dist/renderers/step-line-renderer.js +52 -0
- package/dist/renderers/supertrend-renderer.d.ts +18 -0
- package/dist/renderers/supertrend-renderer.d.ts.map +1 -0
- package/dist/renderers/supertrend-renderer.js +80 -0
- package/dist/renderers/volume-profile-renderer.d.ts +25 -0
- package/dist/renderers/volume-profile-renderer.d.ts.map +1 -0
- package/dist/renderers/volume-profile-renderer.js +83 -0
- package/dist/renderers/watermark-renderer.d.ts +15 -0
- package/dist/renderers/watermark-renderer.d.ts.map +1 -0
- package/dist/renderers/watermark-renderer.js +26 -0
- package/dist/scheduler.d.ts +25 -0
- package/dist/scheduler.d.ts.map +1 -0
- package/dist/scheduler.js +77 -0
- package/package.json +33 -4
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file packages/chart-renderer-canvas/src/index.ts
|
|
3
|
+
* Main entry point for @tranding-custom-chart/renderer-canvas.
|
|
4
|
+
*/
|
|
5
|
+
export * from './dpi.js';
|
|
6
|
+
export * from './scheduler.js';
|
|
7
|
+
export * from './renderers/grid-renderer.js';
|
|
8
|
+
export * from './renderers/candlestick-renderer.js';
|
|
9
|
+
export * from './renderers/line-renderer.js';
|
|
10
|
+
export * from './renderers/bar-renderer.js';
|
|
11
|
+
export * from './renderers/crosshair-renderer.js';
|
|
12
|
+
export * from './renderers/ohlc-bar-renderer.js';
|
|
13
|
+
export * from './renderers/hollow-candlestick-renderer.js';
|
|
14
|
+
export * from './renderers/baseline-renderer.js';
|
|
15
|
+
export * from './renderers/step-line-renderer.js';
|
|
16
|
+
export * from './renderers/high-low-renderer.js';
|
|
17
|
+
export * from './renderers/columns-renderer.js';
|
|
18
|
+
export * from './renderers/line-with-markers-renderer.js';
|
|
19
|
+
export * from './renderers/hlc-area-renderer.js';
|
|
20
|
+
export * from './renderers/watermark-renderer.js';
|
|
21
|
+
export * from './renderers/last-price-renderer.js';
|
|
22
|
+
export * from './renderers/drawing-renderer.js';
|
|
23
|
+
export * from './renderers/pie-renderer.js';
|
|
24
|
+
export * from './renderers/horizontal-bar-renderer.js';
|
|
25
|
+
export * from './renderers/stacked-bar-renderer.js';
|
|
26
|
+
export * from './renderers/curved-line-renderer.js';
|
|
27
|
+
export * from './renderers/radar-renderer.js';
|
|
28
|
+
export * from './renderers/volume-profile-renderer.js';
|
|
29
|
+
export * from './renderers/supertrend-renderer.js';
|
|
30
|
+
export * from './renderers/scatter-renderer.js';
|
|
31
|
+
export * from './renderers/bubble-renderer.js';
|
|
32
|
+
export * from './renderers/polar-area-renderer.js';
|
|
33
|
+
export * from './renderers/box-plot-renderer.js';
|
|
34
|
+
export * from './renderers/heatmap-renderer.js';
|
|
35
|
+
export * from './renderers/mixed-renderer.js';
|
|
36
|
+
export * from './renderers/marker-renderer.js';
|
|
37
|
+
export * from './canvas-engine.js';
|
|
38
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,cAAc,UAAU,CAAC;AACzB,cAAc,gBAAgB,CAAC;AAC/B,cAAc,8BAA8B,CAAC;AAC7C,cAAc,qCAAqC,CAAC;AACpD,cAAc,8BAA8B,CAAC;AAC7C,cAAc,6BAA6B,CAAC;AAC5C,cAAc,mCAAmC,CAAC;AAClD,cAAc,kCAAkC,CAAC;AACjD,cAAc,4CAA4C,CAAC;AAC3D,cAAc,kCAAkC,CAAC;AACjD,cAAc,mCAAmC,CAAC;AAClD,cAAc,kCAAkC,CAAC;AACjD,cAAc,iCAAiC,CAAC;AAChD,cAAc,2CAA2C,CAAC;AAC1D,cAAc,kCAAkC,CAAC;AACjD,cAAc,mCAAmC,CAAC;AAClD,cAAc,oCAAoC,CAAC;AACnD,cAAc,iCAAiC,CAAC;AAChD,cAAc,6BAA6B,CAAC;AAC5C,cAAc,wCAAwC,CAAC;AACvD,cAAc,qCAAqC,CAAC;AACpD,cAAc,qCAAqC,CAAC;AACpD,cAAc,+BAA+B,CAAC;AAC9C,cAAc,wCAAwC,CAAC;AACvD,cAAc,oCAAoC,CAAC;AACnD,cAAc,iCAAiC,CAAC;AAChD,cAAc,gCAAgC,CAAC;AAC/C,cAAc,oCAAoC,CAAC;AACnD,cAAc,kCAAkC,CAAC;AACjD,cAAc,iCAAiC,CAAC;AAChD,cAAc,+BAA+B,CAAC;AAC9C,cAAc,gCAAgC,CAAC;AAC/C,cAAc,oBAAoB,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file packages/chart-renderer-canvas/src/index.ts
|
|
3
|
+
* Main entry point for @tranding-custom-chart/renderer-canvas.
|
|
4
|
+
*/
|
|
5
|
+
export * from './dpi.js';
|
|
6
|
+
export * from './scheduler.js';
|
|
7
|
+
export * from './renderers/grid-renderer.js';
|
|
8
|
+
export * from './renderers/candlestick-renderer.js';
|
|
9
|
+
export * from './renderers/line-renderer.js';
|
|
10
|
+
export * from './renderers/bar-renderer.js';
|
|
11
|
+
export * from './renderers/crosshair-renderer.js';
|
|
12
|
+
export * from './renderers/ohlc-bar-renderer.js';
|
|
13
|
+
export * from './renderers/hollow-candlestick-renderer.js';
|
|
14
|
+
export * from './renderers/baseline-renderer.js';
|
|
15
|
+
export * from './renderers/step-line-renderer.js';
|
|
16
|
+
export * from './renderers/high-low-renderer.js';
|
|
17
|
+
export * from './renderers/columns-renderer.js';
|
|
18
|
+
export * from './renderers/line-with-markers-renderer.js';
|
|
19
|
+
export * from './renderers/hlc-area-renderer.js';
|
|
20
|
+
export * from './renderers/watermark-renderer.js';
|
|
21
|
+
export * from './renderers/last-price-renderer.js';
|
|
22
|
+
export * from './renderers/drawing-renderer.js';
|
|
23
|
+
export * from './renderers/pie-renderer.js';
|
|
24
|
+
export * from './renderers/horizontal-bar-renderer.js';
|
|
25
|
+
export * from './renderers/stacked-bar-renderer.js';
|
|
26
|
+
export * from './renderers/curved-line-renderer.js';
|
|
27
|
+
export * from './renderers/radar-renderer.js';
|
|
28
|
+
export * from './renderers/volume-profile-renderer.js';
|
|
29
|
+
export * from './renderers/supertrend-renderer.js';
|
|
30
|
+
export * from './renderers/scatter-renderer.js';
|
|
31
|
+
export * from './renderers/bubble-renderer.js';
|
|
32
|
+
export * from './renderers/polar-area-renderer.js';
|
|
33
|
+
export * from './renderers/box-plot-renderer.js';
|
|
34
|
+
export * from './renderers/heatmap-renderer.js';
|
|
35
|
+
export * from './renderers/mixed-renderer.js';
|
|
36
|
+
export * from './renderers/marker-renderer.js';
|
|
37
|
+
export * from './canvas-engine.js';
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file packages/chart-renderer-canvas/src/renderers/bar-renderer.ts
|
|
3
|
+
* Bar chart and volume panel renderer.
|
|
4
|
+
*/
|
|
5
|
+
import type { Scale } from '@tranding-custom-chart/core';
|
|
6
|
+
export interface BarItem {
|
|
7
|
+
readonly value: number;
|
|
8
|
+
readonly color?: string | undefined;
|
|
9
|
+
readonly isUp?: boolean | undefined;
|
|
10
|
+
}
|
|
11
|
+
export interface BarRenderOptions {
|
|
12
|
+
readonly ctx: CanvasRenderingContext2D;
|
|
13
|
+
readonly items: readonly (BarItem | null | undefined)[];
|
|
14
|
+
readonly xScale: Scale<number>;
|
|
15
|
+
readonly yScale: Scale<number>;
|
|
16
|
+
readonly baselineY: number;
|
|
17
|
+
readonly dpr: number;
|
|
18
|
+
readonly defaultColor?: string;
|
|
19
|
+
readonly upColor?: string;
|
|
20
|
+
readonly downColor?: string;
|
|
21
|
+
readonly barWidthRatio?: number;
|
|
22
|
+
readonly startIndex?: number;
|
|
23
|
+
readonly endIndex?: number;
|
|
24
|
+
}
|
|
25
|
+
export declare function renderBarSeries(options: BarRenderOptions): void;
|
|
26
|
+
//# sourceMappingURL=bar-renderer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bar-renderer.d.ts","sourceRoot":"","sources":["../../src/renderers/bar-renderer.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,6BAA6B,CAAC;AAGzD,MAAM,WAAW,OAAO;IACtB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACpC,QAAQ,CAAC,IAAI,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;CACrC;AAED,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,GAAG,EAAE,wBAAwB,CAAC;IACvC,QAAQ,CAAC,KAAK,EAAE,SAAS,CAAC,OAAO,GAAG,IAAI,GAAG,SAAS,CAAC,EAAE,CAAC;IACxD,QAAQ,CAAC,MAAM,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC;IAC/B,QAAQ,CAAC,MAAM,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC;IAC/B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,YAAY,CAAC,EAAE,MAAM,CAAC;IAC/B,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,aAAa,CAAC,EAAE,MAAM,CAAC;IAChC,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;CAC5B;AAED,wBAAgB,eAAe,CAAC,OAAO,EAAE,gBAAgB,GAAG,IAAI,CAyD/D"}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file packages/chart-renderer-canvas/src/renderers/bar-renderer.ts
|
|
3
|
+
* Bar chart and volume panel renderer.
|
|
4
|
+
*/
|
|
5
|
+
import { snapRect } from '../dpi.js';
|
|
6
|
+
export function renderBarSeries(options) {
|
|
7
|
+
const { ctx, items, xScale, yScale, baselineY, dpr, defaultColor = '#155c45', upColor = 'rgba(22, 121, 76, 0.45)', downColor = 'rgba(180, 35, 24, 0.45)', barWidthRatio = 0.7, startIndex = 0, endIndex = items.length - 1, } = options;
|
|
8
|
+
if (items.length === 0 || startIndex > endIndex)
|
|
9
|
+
return;
|
|
10
|
+
const start = Math.max(0, startIndex);
|
|
11
|
+
const end = Math.min(items.length - 1, endIndex);
|
|
12
|
+
let slotWidth = 8;
|
|
13
|
+
if ('stepWidth' in xScale && typeof xScale.stepWidth === 'number') {
|
|
14
|
+
slotWidth = xScale.stepWidth;
|
|
15
|
+
}
|
|
16
|
+
else if (items.length > 1) {
|
|
17
|
+
const x0 = xScale.scale(0);
|
|
18
|
+
const x1 = xScale.scale(1);
|
|
19
|
+
slotWidth = Math.abs(x1 - x0) || 8;
|
|
20
|
+
}
|
|
21
|
+
const barWidth = slotWidth < 2 ? Math.max(0.5, slotWidth * 0.8) : Math.max(1, slotWidth * barWidthRatio);
|
|
22
|
+
const halfWidth = barWidth / 2;
|
|
23
|
+
ctx.save();
|
|
24
|
+
for (let i = start; i <= end; i++) {
|
|
25
|
+
const item = items[i];
|
|
26
|
+
if (!item || !Number.isFinite(item.value) || item.value <= 0)
|
|
27
|
+
continue;
|
|
28
|
+
const rawX = xScale.scale(i);
|
|
29
|
+
const barTop = yScale.scale(item.value);
|
|
30
|
+
const height = Math.max(1, Math.abs(baselineY - barTop));
|
|
31
|
+
const leftX = snapRect(rawX - halfWidth, dpr);
|
|
32
|
+
const topY = snapRect(Math.min(baselineY, barTop), dpr);
|
|
33
|
+
if (item.color) {
|
|
34
|
+
ctx.fillStyle = item.color;
|
|
35
|
+
}
|
|
36
|
+
else if (item.isUp !== undefined) {
|
|
37
|
+
ctx.fillStyle = item.isUp ? upColor : downColor;
|
|
38
|
+
}
|
|
39
|
+
else {
|
|
40
|
+
ctx.fillStyle = defaultColor;
|
|
41
|
+
}
|
|
42
|
+
ctx.fillRect(leftX, topY, barWidth, height);
|
|
43
|
+
}
|
|
44
|
+
ctx.restore();
|
|
45
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file packages/chart-renderer-canvas/src/renderers/baseline-renderer.ts
|
|
3
|
+
* Two-zone baseline chart splitting returns into bullish (above) and bearish (below) zones.
|
|
4
|
+
*/
|
|
5
|
+
import type { Dimension, Padding, Scale } from '@tranding-custom-chart/core';
|
|
6
|
+
export interface BaselineRenderOptions {
|
|
7
|
+
readonly ctx: CanvasRenderingContext2D;
|
|
8
|
+
readonly data: readonly number[];
|
|
9
|
+
readonly xScale: Scale<number>;
|
|
10
|
+
readonly yScale: Scale<number>;
|
|
11
|
+
readonly baselineValue: number;
|
|
12
|
+
readonly bounds: Dimension;
|
|
13
|
+
readonly padding: Padding;
|
|
14
|
+
readonly dpr: number;
|
|
15
|
+
readonly aboveColor?: string | undefined;
|
|
16
|
+
readonly belowColor?: string | undefined;
|
|
17
|
+
readonly lineWidth?: number | undefined;
|
|
18
|
+
}
|
|
19
|
+
export declare function renderBaselineChart(options: BaselineRenderOptions): void;
|
|
20
|
+
//# sourceMappingURL=baseline-renderer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"baseline-renderer.d.ts","sourceRoot":"","sources":["../../src/renderers/baseline-renderer.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,SAAS,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,6BAA6B,CAAC;AAG7E,MAAM,WAAW,qBAAqB;IACpC,QAAQ,CAAC,GAAG,EAAE,wBAAwB,CAAC;IACvC,QAAQ,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,CAAC;IACjC,QAAQ,CAAC,MAAM,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC;IAC/B,QAAQ,CAAC,MAAM,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC;IAC/B,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;IAC/B,QAAQ,CAAC,MAAM,EAAE,SAAS,CAAC;IAC3B,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;IAC1B,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACzC,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACzC,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CACzC;AAED,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,qBAAqB,GAAG,IAAI,CAyHxE"}
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file packages/chart-renderer-canvas/src/renderers/baseline-renderer.ts
|
|
3
|
+
* Two-zone baseline chart splitting returns into bullish (above) and bearish (below) zones.
|
|
4
|
+
*/
|
|
5
|
+
import { snapLine } from '../dpi.js';
|
|
6
|
+
export function renderBaselineChart(options) {
|
|
7
|
+
const { ctx, data, xScale, yScale, baselineValue, bounds, padding, dpr, aboveColor = '#16794c', belowColor = '#b42318', lineWidth = 2, } = options;
|
|
8
|
+
if (data.length === 0)
|
|
9
|
+
return;
|
|
10
|
+
const yBase = snapLine(yScale.scale(baselineValue), dpr);
|
|
11
|
+
const chartLeft = padding.left;
|
|
12
|
+
const chartRight = bounds.width - padding.right;
|
|
13
|
+
const chartTop = padding.top;
|
|
14
|
+
const chartBottom = bounds.height - padding.bottom;
|
|
15
|
+
// Build the continuous polyline points
|
|
16
|
+
const points = [];
|
|
17
|
+
for (let i = 0; i < data.length; i++) {
|
|
18
|
+
const val = data[i];
|
|
19
|
+
if (Number.isFinite(val)) {
|
|
20
|
+
points.push({
|
|
21
|
+
x: xScale.scale(i),
|
|
22
|
+
y: yScale.scale(val),
|
|
23
|
+
});
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
if (points.length < 2)
|
|
27
|
+
return;
|
|
28
|
+
ctx.save();
|
|
29
|
+
// 1. Render Upper Zone (Above Baseline)
|
|
30
|
+
ctx.save();
|
|
31
|
+
ctx.beginPath();
|
|
32
|
+
ctx.rect(chartLeft, chartTop, chartRight - chartLeft, Math.max(0, yBase - chartTop));
|
|
33
|
+
ctx.clip();
|
|
34
|
+
// Upper gradient fill
|
|
35
|
+
const upperGrad = ctx.createLinearGradient(0, chartTop, 0, yBase);
|
|
36
|
+
upperGrad.addColorStop(0, 'rgba(22, 121, 76, 0.40)');
|
|
37
|
+
upperGrad.addColorStop(1, 'rgba(22, 121, 76, 0.02)');
|
|
38
|
+
ctx.fillStyle = upperGrad;
|
|
39
|
+
ctx.beginPath();
|
|
40
|
+
ctx.moveTo(points[0].x, yBase);
|
|
41
|
+
for (const pt of points) {
|
|
42
|
+
ctx.lineTo(pt.x, pt.y);
|
|
43
|
+
}
|
|
44
|
+
ctx.lineTo(points[points.length - 1].x, yBase);
|
|
45
|
+
ctx.closePath();
|
|
46
|
+
ctx.fill();
|
|
47
|
+
// Upper stroke
|
|
48
|
+
ctx.strokeStyle = aboveColor;
|
|
49
|
+
ctx.lineWidth = lineWidth;
|
|
50
|
+
ctx.beginPath();
|
|
51
|
+
ctx.moveTo(points[0].x, points[0].y);
|
|
52
|
+
for (let i = 1; i < points.length; i++) {
|
|
53
|
+
ctx.lineTo(points[i].x, points[i].y);
|
|
54
|
+
}
|
|
55
|
+
ctx.stroke();
|
|
56
|
+
ctx.restore();
|
|
57
|
+
// 2. Render Lower Zone (Below Baseline)
|
|
58
|
+
ctx.save();
|
|
59
|
+
ctx.beginPath();
|
|
60
|
+
ctx.rect(chartLeft, yBase, chartRight - chartLeft, Math.max(0, chartBottom - yBase));
|
|
61
|
+
ctx.clip();
|
|
62
|
+
// Lower gradient fill
|
|
63
|
+
const lowerGrad = ctx.createLinearGradient(0, yBase, 0, chartBottom);
|
|
64
|
+
lowerGrad.addColorStop(0, 'rgba(180, 35, 24, 0.02)');
|
|
65
|
+
lowerGrad.addColorStop(1, 'rgba(180, 35, 24, 0.40)');
|
|
66
|
+
ctx.fillStyle = lowerGrad;
|
|
67
|
+
ctx.beginPath();
|
|
68
|
+
ctx.moveTo(points[0].x, yBase);
|
|
69
|
+
for (const pt of points) {
|
|
70
|
+
ctx.lineTo(pt.x, pt.y);
|
|
71
|
+
}
|
|
72
|
+
ctx.lineTo(points[points.length - 1].x, yBase);
|
|
73
|
+
ctx.closePath();
|
|
74
|
+
ctx.fill();
|
|
75
|
+
// Lower stroke
|
|
76
|
+
ctx.strokeStyle = belowColor;
|
|
77
|
+
ctx.lineWidth = lineWidth;
|
|
78
|
+
ctx.beginPath();
|
|
79
|
+
ctx.moveTo(points[0].x, points[0].y);
|
|
80
|
+
for (let i = 1; i < points.length; i++) {
|
|
81
|
+
ctx.lineTo(points[i].x, points[i].y);
|
|
82
|
+
}
|
|
83
|
+
ctx.stroke();
|
|
84
|
+
ctx.restore();
|
|
85
|
+
// 3. Render Baseline Reference Line
|
|
86
|
+
ctx.strokeStyle = 'rgba(255, 255, 255, 0.35)';
|
|
87
|
+
ctx.lineWidth = 1;
|
|
88
|
+
ctx.setLineDash([4, 4]);
|
|
89
|
+
ctx.beginPath();
|
|
90
|
+
ctx.moveTo(chartLeft, yBase);
|
|
91
|
+
ctx.lineTo(chartRight, yBase);
|
|
92
|
+
ctx.stroke();
|
|
93
|
+
// Baseline Badge on Price Axis
|
|
94
|
+
ctx.setLineDash([]);
|
|
95
|
+
ctx.fillStyle = 'rgba(255, 255, 255, 0.8)';
|
|
96
|
+
ctx.font = '10px monospace';
|
|
97
|
+
ctx.textAlign = 'left';
|
|
98
|
+
ctx.textBaseline = 'middle';
|
|
99
|
+
ctx.fillText(`Base: ${baselineValue.toFixed(1)}`, chartRight + 4, yBase);
|
|
100
|
+
ctx.restore();
|
|
101
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file packages/chart-renderer-canvas/src/renderers/box-plot-renderer.ts
|
|
3
|
+
* High-performance Canvas 2D statistical box plot (box-and-whisker) renderer.
|
|
4
|
+
*/
|
|
5
|
+
import type { BoxPlotDatum, Scale } from '@tranding-custom-chart/core';
|
|
6
|
+
export interface BoxPlotRenderOptions {
|
|
7
|
+
readonly boxWidthRatio?: number | undefined;
|
|
8
|
+
readonly capWidthRatio?: number | undefined;
|
|
9
|
+
readonly defaultColor?: string | undefined;
|
|
10
|
+
readonly strokeWidth?: number | undefined;
|
|
11
|
+
readonly medianColor?: string | undefined;
|
|
12
|
+
}
|
|
13
|
+
export declare function renderBoxPlots(ctx: CanvasRenderingContext2D, data: readonly BoxPlotDatum[], xScale: Scale<number>, yScale: Scale<number>, options?: BoxPlotRenderOptions): void;
|
|
14
|
+
//# sourceMappingURL=box-plot-renderer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"box-plot-renderer.d.ts","sourceRoot":"","sources":["../../src/renderers/box-plot-renderer.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,KAAK,EAAE,MAAM,6BAA6B,CAAC;AAEvE,MAAM,WAAW,oBAAoB;IACnC,QAAQ,CAAC,aAAa,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC5C,QAAQ,CAAC,aAAa,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC5C,QAAQ,CAAC,YAAY,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC3C,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC1C,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CAC3C;AAED,wBAAgB,cAAc,CAC5B,GAAG,EAAE,wBAAwB,EAC7B,IAAI,EAAE,SAAS,YAAY,EAAE,EAC7B,MAAM,EAAE,KAAK,CAAC,MAAM,CAAC,EACrB,MAAM,EAAE,KAAK,CAAC,MAAM,CAAC,EACrB,OAAO,GAAE,oBAAyB,GACjC,IAAI,CAyFN"}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file packages/chart-renderer-canvas/src/renderers/box-plot-renderer.ts
|
|
3
|
+
* High-performance Canvas 2D statistical box plot (box-and-whisker) renderer.
|
|
4
|
+
*/
|
|
5
|
+
export function renderBoxPlots(ctx, data, xScale, yScale, options = {}) {
|
|
6
|
+
if (data.length === 0)
|
|
7
|
+
return;
|
|
8
|
+
const { boxWidthRatio = 0.5, capWidthRatio = 0.25, defaultColor = '#3b82f6', strokeWidth = 1.5, medianColor = '#ffffff', } = options;
|
|
9
|
+
ctx.save();
|
|
10
|
+
ctx.lineWidth = strokeWidth;
|
|
11
|
+
const count = data.length;
|
|
12
|
+
// Step width estimate between categories
|
|
13
|
+
let slotWidth = 40;
|
|
14
|
+
if (count > 1) {
|
|
15
|
+
slotWidth = Math.abs(xScale.scale(1) - xScale.scale(0));
|
|
16
|
+
}
|
|
17
|
+
else {
|
|
18
|
+
slotWidth = 60;
|
|
19
|
+
}
|
|
20
|
+
const boxHalfWidth = Math.max(4, (slotWidth * boxWidthRatio) / 2);
|
|
21
|
+
const capHalfWidth = Math.max(3, (slotWidth * capWidthRatio) / 2);
|
|
22
|
+
for (let i = 0; i < count; i++) {
|
|
23
|
+
const datum = data[i];
|
|
24
|
+
const cx = Math.round(xScale.scale(i));
|
|
25
|
+
const yMin = yScale.scale(datum.min);
|
|
26
|
+
const yQ1 = yScale.scale(datum.q1);
|
|
27
|
+
const yMedian = yScale.scale(datum.median);
|
|
28
|
+
const yQ3 = yScale.scale(datum.q3);
|
|
29
|
+
const yMax = yScale.scale(datum.max);
|
|
30
|
+
const baseColor = datum.color ?? defaultColor;
|
|
31
|
+
// 1. Whisker lines (from min to Q1 and Q3 to max)
|
|
32
|
+
ctx.strokeStyle = baseColor;
|
|
33
|
+
ctx.beginPath();
|
|
34
|
+
// Lower whisker
|
|
35
|
+
ctx.moveTo(cx, yMin);
|
|
36
|
+
ctx.lineTo(cx, yQ1);
|
|
37
|
+
// Lower cap
|
|
38
|
+
ctx.moveTo(cx - capHalfWidth, yMin);
|
|
39
|
+
ctx.lineTo(cx + capHalfWidth, yMin);
|
|
40
|
+
// Upper whisker
|
|
41
|
+
ctx.moveTo(cx, yQ3);
|
|
42
|
+
ctx.lineTo(cx, yMax);
|
|
43
|
+
// Upper cap
|
|
44
|
+
ctx.moveTo(cx - capHalfWidth, yMax);
|
|
45
|
+
ctx.lineTo(cx + capHalfWidth, yMax);
|
|
46
|
+
ctx.stroke();
|
|
47
|
+
// 2. Interquartile Range (IQR) Box: [Q3 to Q1] (Note: yQ3 is pixel-top, yQ1 is pixel-bottom)
|
|
48
|
+
const boxTop = Math.min(yQ1, yQ3);
|
|
49
|
+
const boxHeight = Math.max(1, Math.abs(yQ1 - yQ3));
|
|
50
|
+
const boxLeft = cx - boxHalfWidth;
|
|
51
|
+
// Box fill
|
|
52
|
+
ctx.fillStyle = baseColor.startsWith('#') ? `${baseColor}44` : 'rgba(59, 130, 246, 0.25)';
|
|
53
|
+
ctx.fillRect(boxLeft, boxTop, boxHalfWidth * 2, boxHeight);
|
|
54
|
+
// Box outline
|
|
55
|
+
ctx.strokeRect(boxLeft, boxTop, boxHalfWidth * 2, boxHeight);
|
|
56
|
+
// 3. Median Line
|
|
57
|
+
ctx.strokeStyle = medianColor;
|
|
58
|
+
ctx.beginPath();
|
|
59
|
+
ctx.moveTo(boxLeft, yMedian);
|
|
60
|
+
ctx.lineTo(boxLeft + boxHalfWidth * 2, yMedian);
|
|
61
|
+
ctx.stroke();
|
|
62
|
+
// 4. Outlier points (if any)
|
|
63
|
+
if (datum.outliers && datum.outliers.length > 0) {
|
|
64
|
+
ctx.fillStyle = '#ef4444';
|
|
65
|
+
ctx.strokeStyle = '#ffffff';
|
|
66
|
+
for (const outlier of datum.outliers) {
|
|
67
|
+
const yOut = yScale.scale(outlier);
|
|
68
|
+
ctx.beginPath();
|
|
69
|
+
ctx.arc(cx, yOut, 3, 0, Math.PI * 2);
|
|
70
|
+
ctx.fill();
|
|
71
|
+
ctx.stroke();
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
ctx.restore();
|
|
76
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file packages/chart-renderer-canvas/src/renderers/bubble-renderer.ts
|
|
3
|
+
* High-performance 2D Canvas renderer for Bubble Charts.
|
|
4
|
+
*/
|
|
5
|
+
import type { Scale, BubbleDatum } from '@tranding-custom-chart/core';
|
|
6
|
+
export interface BubbleRenderOptions {
|
|
7
|
+
readonly minRadius?: number;
|
|
8
|
+
readonly maxRadius?: number;
|
|
9
|
+
readonly defaultColor?: string;
|
|
10
|
+
readonly strokeColor?: string;
|
|
11
|
+
readonly strokeWidth?: number;
|
|
12
|
+
}
|
|
13
|
+
export declare function renderBubbles(ctx: CanvasRenderingContext2D, data: readonly BubbleDatum[], xScale: Scale<number>, yScale: Scale<number>, options?: BubbleRenderOptions): void;
|
|
14
|
+
//# sourceMappingURL=bubble-renderer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bubble-renderer.d.ts","sourceRoot":"","sources":["../../src/renderers/bubble-renderer.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,KAAK,EAAE,WAAW,EAAE,MAAM,6BAA6B,CAAC;AAEtE,MAAM,WAAW,mBAAmB;IAClC,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,YAAY,CAAC,EAAE,MAAM,CAAC;IAC/B,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC;CAC/B;AAED,wBAAgB,aAAa,CAC3B,GAAG,EAAE,wBAAwB,EAC7B,IAAI,EAAE,SAAS,WAAW,EAAE,EAC5B,MAAM,EAAE,KAAK,CAAC,MAAM,CAAC,EACrB,MAAM,EAAE,KAAK,CAAC,MAAM,CAAC,EACrB,OAAO,GAAE,mBAAwB,GAChC,IAAI,CAqCN"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file packages/chart-renderer-canvas/src/renderers/bubble-renderer.ts
|
|
3
|
+
* High-performance 2D Canvas renderer for Bubble Charts.
|
|
4
|
+
*/
|
|
5
|
+
export function renderBubbles(ctx, data, xScale, yScale, options = {}) {
|
|
6
|
+
if (!data || data.length === 0)
|
|
7
|
+
return;
|
|
8
|
+
const defaultColor = options.defaultColor ?? 'rgba(59, 130, 246, 0.6)';
|
|
9
|
+
const strokeColor = options.strokeColor ?? 'rgba(59, 130, 246, 0.9)';
|
|
10
|
+
const strokeWidth = options.strokeWidth ?? 1.5;
|
|
11
|
+
const minRadius = options.minRadius ?? 3;
|
|
12
|
+
const maxRadius = options.maxRadius ?? 40;
|
|
13
|
+
ctx.save();
|
|
14
|
+
ctx.lineWidth = strokeWidth;
|
|
15
|
+
for (let i = 0; i < data.length; i++) {
|
|
16
|
+
const d = data[i];
|
|
17
|
+
const px = xScale.scale(d.x);
|
|
18
|
+
const py = yScale.scale(d.y);
|
|
19
|
+
const radius = Math.max(minRadius, Math.min(maxRadius, d.r));
|
|
20
|
+
ctx.beginPath();
|
|
21
|
+
ctx.arc(px, py, radius, 0, Math.PI * 2);
|
|
22
|
+
ctx.fillStyle = d.color ?? defaultColor;
|
|
23
|
+
ctx.strokeStyle = strokeColor;
|
|
24
|
+
ctx.fill();
|
|
25
|
+
if (strokeWidth > 0) {
|
|
26
|
+
ctx.stroke();
|
|
27
|
+
}
|
|
28
|
+
if (d.label) {
|
|
29
|
+
ctx.fillStyle = '#ffffff';
|
|
30
|
+
ctx.font = '10px system-ui, sans-serif';
|
|
31
|
+
ctx.textAlign = 'center';
|
|
32
|
+
ctx.textBaseline = 'middle';
|
|
33
|
+
ctx.fillText(d.label, px, py);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
ctx.restore();
|
|
37
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file packages/chart-renderer-canvas/src/renderers/candlestick-renderer.ts
|
|
3
|
+
* High-performance batched candlestick renderer.
|
|
4
|
+
*/
|
|
5
|
+
import type { ChartTheme, OHLCVBar, Scale } from '@tranding-custom-chart/core';
|
|
6
|
+
export interface CandlestickRenderOptions {
|
|
7
|
+
readonly ctx: CanvasRenderingContext2D;
|
|
8
|
+
readonly bars: readonly OHLCVBar[];
|
|
9
|
+
readonly xScale: Scale<number>;
|
|
10
|
+
readonly yScale: Scale<number>;
|
|
11
|
+
readonly theme: ChartTheme;
|
|
12
|
+
readonly dpr: number;
|
|
13
|
+
readonly startIndex?: number;
|
|
14
|
+
readonly endIndex?: number;
|
|
15
|
+
readonly candleWidthRatio?: number;
|
|
16
|
+
}
|
|
17
|
+
export declare function renderCandlesticks(options: CandlestickRenderOptions): void;
|
|
18
|
+
//# sourceMappingURL=candlestick-renderer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"candlestick-renderer.d.ts","sourceRoot":"","sources":["../../src/renderers/candlestick-renderer.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,QAAQ,EAAE,KAAK,EAAE,MAAM,6BAA6B,CAAC;AAG/E,MAAM,WAAW,wBAAwB;IACvC,QAAQ,CAAC,GAAG,EAAE,wBAAwB,CAAC;IACvC,QAAQ,CAAC,IAAI,EAAE,SAAS,QAAQ,EAAE,CAAC;IACnC,QAAQ,CAAC,MAAM,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC;IAC/B,QAAQ,CAAC,MAAM,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC;IAC/B,QAAQ,CAAC,KAAK,EAAE,UAAU,CAAC;IAC3B,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,gBAAgB,CAAC,EAAE,MAAM,CAAC;CACpC;AAED,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,wBAAwB,GAAG,IAAI,CAwG1E"}
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file packages/chart-renderer-canvas/src/renderers/candlestick-renderer.ts
|
|
3
|
+
* High-performance batched candlestick renderer.
|
|
4
|
+
*/
|
|
5
|
+
import { snapLine, snapRect } from '../dpi.js';
|
|
6
|
+
export function renderCandlesticks(options) {
|
|
7
|
+
const { ctx, bars, xScale, yScale, theme, dpr, startIndex = 0, endIndex = bars.length - 1, candleWidthRatio = 0.7, } = options;
|
|
8
|
+
if (bars.length === 0 || startIndex > endIndex)
|
|
9
|
+
return;
|
|
10
|
+
const start = Math.max(0, startIndex);
|
|
11
|
+
const end = Math.min(bars.length - 1, endIndex);
|
|
12
|
+
// Determine bar width from scale
|
|
13
|
+
let slotWidth = 8;
|
|
14
|
+
if ('stepWidth' in xScale && typeof xScale.stepWidth === 'number') {
|
|
15
|
+
slotWidth = xScale.stepWidth;
|
|
16
|
+
}
|
|
17
|
+
else if (bars.length > 1) {
|
|
18
|
+
const x0 = xScale.scale(0);
|
|
19
|
+
const x1 = xScale.scale(1);
|
|
20
|
+
slotWidth = Math.abs(x1 - x0) || 8;
|
|
21
|
+
}
|
|
22
|
+
const candleWidth = slotWidth < 2 ? Math.max(0.5, slotWidth * 0.8) : Math.max(1, slotWidth * candleWidthRatio);
|
|
23
|
+
const halfWidth = candleWidth / 2;
|
|
24
|
+
ctx.save();
|
|
25
|
+
ctx.lineWidth = slotWidth < 2 ? 0.75 : 1;
|
|
26
|
+
// Render Bullish (Up) Candles
|
|
27
|
+
ctx.strokeStyle = theme.upCandle;
|
|
28
|
+
ctx.fillStyle = theme.upCandle;
|
|
29
|
+
ctx.beginPath();
|
|
30
|
+
for (let i = start; i <= end; i++) {
|
|
31
|
+
const b = bars[i];
|
|
32
|
+
if (b.close < b.open)
|
|
33
|
+
continue; // Skip bearish
|
|
34
|
+
const rawX = xScale.scale(i);
|
|
35
|
+
const x = snapLine(rawX, dpr);
|
|
36
|
+
const highY = snapLine(yScale.scale(b.high), dpr);
|
|
37
|
+
const lowY = snapLine(yScale.scale(b.low), dpr);
|
|
38
|
+
// Wick line
|
|
39
|
+
ctx.moveTo(x, highY);
|
|
40
|
+
ctx.lineTo(x, lowY);
|
|
41
|
+
}
|
|
42
|
+
ctx.stroke();
|
|
43
|
+
// Bullish Bodies
|
|
44
|
+
for (let i = start; i <= end; i++) {
|
|
45
|
+
const b = bars[i];
|
|
46
|
+
if (b.close < b.open)
|
|
47
|
+
continue;
|
|
48
|
+
const rawX = xScale.scale(i);
|
|
49
|
+
const openY = yScale.scale(b.open);
|
|
50
|
+
const closeY = yScale.scale(b.close);
|
|
51
|
+
const topY = snapRect(Math.min(openY, closeY), dpr);
|
|
52
|
+
const bodyHeight = Math.max(1.5, Math.abs(closeY - openY));
|
|
53
|
+
const leftX = snapRect(rawX - halfWidth, dpr);
|
|
54
|
+
ctx.fillRect(leftX, topY, candleWidth, bodyHeight);
|
|
55
|
+
}
|
|
56
|
+
// Render Bearish (Down) Candles
|
|
57
|
+
ctx.strokeStyle = theme.downCandle;
|
|
58
|
+
ctx.fillStyle = theme.downCandle;
|
|
59
|
+
ctx.beginPath();
|
|
60
|
+
for (let i = start; i <= end; i++) {
|
|
61
|
+
const b = bars[i];
|
|
62
|
+
if (b.close >= b.open)
|
|
63
|
+
continue; // Skip bullish
|
|
64
|
+
const rawX = xScale.scale(i);
|
|
65
|
+
const x = snapLine(rawX, dpr);
|
|
66
|
+
const highY = snapLine(yScale.scale(b.high), dpr);
|
|
67
|
+
const lowY = snapLine(yScale.scale(b.low), dpr);
|
|
68
|
+
// Wick line
|
|
69
|
+
ctx.moveTo(x, highY);
|
|
70
|
+
ctx.lineTo(x, lowY);
|
|
71
|
+
}
|
|
72
|
+
ctx.stroke();
|
|
73
|
+
// Bearish Bodies
|
|
74
|
+
for (let i = start; i <= end; i++) {
|
|
75
|
+
const b = bars[i];
|
|
76
|
+
if (b.close >= b.open)
|
|
77
|
+
continue;
|
|
78
|
+
const rawX = xScale.scale(i);
|
|
79
|
+
const openY = yScale.scale(b.open);
|
|
80
|
+
const closeY = yScale.scale(b.close);
|
|
81
|
+
const topY = snapRect(Math.min(openY, closeY), dpr);
|
|
82
|
+
const bodyHeight = Math.max(1.5, Math.abs(closeY - openY));
|
|
83
|
+
const leftX = snapRect(rawX - halfWidth, dpr);
|
|
84
|
+
ctx.fillRect(leftX, topY, candleWidth, bodyHeight);
|
|
85
|
+
}
|
|
86
|
+
ctx.restore();
|
|
87
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file packages/chart-renderer-canvas/src/renderers/columns-renderer.ts
|
|
3
|
+
* Canvas 2D renderer for vertical Columns charts.
|
|
4
|
+
* Draws vertical columns from scale baseline to close price with bullish/bearish color coding.
|
|
5
|
+
*/
|
|
6
|
+
import type { ChartTheme, OHLCVBar, Scale } from '@tranding-custom-chart/core';
|
|
7
|
+
export interface ColumnsRenderOptions {
|
|
8
|
+
readonly ctx: CanvasRenderingContext2D;
|
|
9
|
+
readonly bars: readonly OHLCVBar[];
|
|
10
|
+
readonly xScale: Scale<number>;
|
|
11
|
+
readonly yScale: Scale<number>;
|
|
12
|
+
readonly baselineY: number;
|
|
13
|
+
readonly theme?: ChartTheme | undefined;
|
|
14
|
+
readonly upColor?: string | undefined;
|
|
15
|
+
readonly downColor?: string | undefined;
|
|
16
|
+
readonly columnWidthRatio?: number | undefined;
|
|
17
|
+
readonly startIndex?: number | undefined;
|
|
18
|
+
readonly endIndex?: number | undefined;
|
|
19
|
+
}
|
|
20
|
+
export declare function renderColumns(options: ColumnsRenderOptions): void;
|
|
21
|
+
//# sourceMappingURL=columns-renderer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"columns-renderer.d.ts","sourceRoot":"","sources":["../../src/renderers/columns-renderer.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,QAAQ,EAAE,KAAK,EAAE,MAAM,6BAA6B,CAAC;AAG/E,MAAM,WAAW,oBAAoB;IACnC,QAAQ,CAAC,GAAG,EAAE,wBAAwB,CAAC;IACvC,QAAQ,CAAC,IAAI,EAAE,SAAS,QAAQ,EAAE,CAAC;IACnC,QAAQ,CAAC,MAAM,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC;IAC/B,QAAQ,CAAC,MAAM,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC;IAC/B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,KAAK,CAAC,EAAE,UAAU,GAAG,SAAS,CAAC;IACxC,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACtC,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACxC,QAAQ,CAAC,gBAAgB,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC/C,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACzC,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CACxC;AAED,wBAAgB,aAAa,CAAC,OAAO,EAAE,oBAAoB,GAAG,IAAI,CA8CjE"}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file packages/chart-renderer-canvas/src/renderers/columns-renderer.ts
|
|
3
|
+
* Canvas 2D renderer for vertical Columns charts.
|
|
4
|
+
* Draws vertical columns from scale baseline to close price with bullish/bearish color coding.
|
|
5
|
+
*/
|
|
6
|
+
import { snapRect } from '../dpi.js';
|
|
7
|
+
export function renderColumns(options) {
|
|
8
|
+
const { ctx, bars, xScale, yScale, baselineY, theme, upColor = theme?.upCandle ?? '#16794c', downColor = theme?.downCandle ?? '#b42318', columnWidthRatio = 0.75, startIndex = 0, endIndex = bars.length - 1, } = options;
|
|
9
|
+
if (bars.length === 0 || startIndex > endIndex)
|
|
10
|
+
return;
|
|
11
|
+
const start = Math.max(0, startIndex);
|
|
12
|
+
const end = Math.min(bars.length - 1, endIndex);
|
|
13
|
+
// Approximate slot width from scale difference
|
|
14
|
+
const x0 = xScale.scale(0);
|
|
15
|
+
const x1 = bars.length > 1 ? xScale.scale(1) : x0 + 10;
|
|
16
|
+
const actualSlot = bars.length > 1 ? Math.abs(x1 - x0) : 10;
|
|
17
|
+
const colWidth = actualSlot < 2 ? Math.max(0.5, actualSlot * 0.8) : Math.max(1, Math.round(actualSlot * columnWidthRatio));
|
|
18
|
+
ctx.save();
|
|
19
|
+
for (let i = start; i <= end; i++) {
|
|
20
|
+
const bar = bars[i];
|
|
21
|
+
const cx = xScale.scale(i);
|
|
22
|
+
const cy = yScale.scale(bar.close);
|
|
23
|
+
const isUp = bar.close >= bar.open;
|
|
24
|
+
ctx.fillStyle = isUp ? upColor : downColor;
|
|
25
|
+
const left = cx - colWidth / 2;
|
|
26
|
+
const top = Math.min(cy, baselineY);
|
|
27
|
+
const height = Math.abs(baselineY - cy);
|
|
28
|
+
const rx = snapRect(left);
|
|
29
|
+
const ry = snapRect(top);
|
|
30
|
+
const rw = snapRect(colWidth);
|
|
31
|
+
const rh = snapRect(Math.max(1, height));
|
|
32
|
+
ctx.fillRect(rx, ry, rw, rh);
|
|
33
|
+
}
|
|
34
|
+
ctx.restore();
|
|
35
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file packages/chart-renderer-canvas/src/renderers/crosshair-renderer.ts
|
|
3
|
+
* Interactive crosshair guidelines, price/time axis badges, and highlight markers.
|
|
4
|
+
*/
|
|
5
|
+
import type { ChartTheme, Dimension, Padding } from '@tranding-custom-chart/core';
|
|
6
|
+
export interface CrosshairRenderOptions {
|
|
7
|
+
readonly ctx: CanvasRenderingContext2D;
|
|
8
|
+
readonly bounds: Dimension;
|
|
9
|
+
readonly padding: Padding;
|
|
10
|
+
readonly x: number;
|
|
11
|
+
readonly y: number;
|
|
12
|
+
readonly theme: ChartTheme;
|
|
13
|
+
readonly dpr: number;
|
|
14
|
+
readonly xLabel?: string | undefined;
|
|
15
|
+
readonly yLabel?: string | undefined;
|
|
16
|
+
readonly showHorizontalLine?: boolean | undefined;
|
|
17
|
+
}
|
|
18
|
+
export declare function renderCrosshair(options: CrosshairRenderOptions): void;
|
|
19
|
+
//# sourceMappingURL=crosshair-renderer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"crosshair-renderer.d.ts","sourceRoot":"","sources":["../../src/renderers/crosshair-renderer.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,SAAS,EAAE,OAAO,EAAE,MAAM,6BAA6B,CAAC;AAGlF,MAAM,WAAW,sBAAsB;IACrC,QAAQ,CAAC,GAAG,EAAE,wBAAwB,CAAC;IACvC,QAAQ,CAAC,MAAM,EAAE,SAAS,CAAC;IAC3B,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;IAC1B,QAAQ,CAAC,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,KAAK,EAAE,UAAU,CAAC;IAC3B,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACrC,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACrC,QAAQ,CAAC,kBAAkB,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;CACnD;AAED,wBAAgB,eAAe,CAAC,OAAO,EAAE,sBAAsB,GAAG,IAAI,CA6ErE"}
|