@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.
Files changed (104) hide show
  1. package/README.md +40 -2
  2. package/dist/canvas-engine.d.ts +82 -0
  3. package/dist/canvas-engine.d.ts.map +1 -0
  4. package/dist/canvas-engine.js +594 -0
  5. package/dist/dpi.d.ts +31 -0
  6. package/dist/dpi.d.ts.map +1 -0
  7. package/dist/dpi.js +65 -0
  8. package/dist/index.d.ts +38 -0
  9. package/dist/index.d.ts.map +1 -0
  10. package/dist/index.js +37 -0
  11. package/dist/renderers/bar-renderer.d.ts +26 -0
  12. package/dist/renderers/bar-renderer.d.ts.map +1 -0
  13. package/dist/renderers/bar-renderer.js +45 -0
  14. package/dist/renderers/baseline-renderer.d.ts +20 -0
  15. package/dist/renderers/baseline-renderer.d.ts.map +1 -0
  16. package/dist/renderers/baseline-renderer.js +101 -0
  17. package/dist/renderers/box-plot-renderer.d.ts +14 -0
  18. package/dist/renderers/box-plot-renderer.d.ts.map +1 -0
  19. package/dist/renderers/box-plot-renderer.js +76 -0
  20. package/dist/renderers/bubble-renderer.d.ts +14 -0
  21. package/dist/renderers/bubble-renderer.d.ts.map +1 -0
  22. package/dist/renderers/bubble-renderer.js +37 -0
  23. package/dist/renderers/candlestick-renderer.d.ts +18 -0
  24. package/dist/renderers/candlestick-renderer.d.ts.map +1 -0
  25. package/dist/renderers/candlestick-renderer.js +87 -0
  26. package/dist/renderers/columns-renderer.d.ts +21 -0
  27. package/dist/renderers/columns-renderer.d.ts.map +1 -0
  28. package/dist/renderers/columns-renderer.js +35 -0
  29. package/dist/renderers/crosshair-renderer.d.ts +19 -0
  30. package/dist/renderers/crosshair-renderer.d.ts.map +1 -0
  31. package/dist/renderers/crosshair-renderer.js +71 -0
  32. package/dist/renderers/curved-line-renderer.d.ts +17 -0
  33. package/dist/renderers/curved-line-renderer.d.ts.map +1 -0
  34. package/dist/renderers/curved-line-renderer.js +46 -0
  35. package/dist/renderers/drawing-renderer.d.ts +19 -0
  36. package/dist/renderers/drawing-renderer.d.ts.map +1 -0
  37. package/dist/renderers/drawing-renderer.js +487 -0
  38. package/dist/renderers/grid-renderer.d.ts +26 -0
  39. package/dist/renderers/grid-renderer.d.ts.map +1 -0
  40. package/dist/renderers/grid-renderer.js +103 -0
  41. package/dist/renderers/heatmap-renderer.d.ts +16 -0
  42. package/dist/renderers/heatmap-renderer.d.ts.map +1 -0
  43. package/dist/renderers/heatmap-renderer.js +80 -0
  44. package/dist/renderers/high-low-renderer.d.ts +19 -0
  45. package/dist/renderers/high-low-renderer.d.ts.map +1 -0
  46. package/dist/renderers/high-low-renderer.js +28 -0
  47. package/dist/renderers/hlc-area-renderer.d.ts +22 -0
  48. package/dist/renderers/hlc-area-renderer.d.ts.map +1 -0
  49. package/dist/renderers/hlc-area-renderer.js +72 -0
  50. package/dist/renderers/hollow-candlestick-renderer.d.ts +26 -0
  51. package/dist/renderers/hollow-candlestick-renderer.d.ts.map +1 -0
  52. package/dist/renderers/hollow-candlestick-renderer.js +71 -0
  53. package/dist/renderers/horizontal-bar-renderer.d.ts +25 -0
  54. package/dist/renderers/horizontal-bar-renderer.d.ts.map +1 -0
  55. package/dist/renderers/horizontal-bar-renderer.js +52 -0
  56. package/dist/renderers/last-price-renderer.d.ts +17 -0
  57. package/dist/renderers/last-price-renderer.d.ts.map +1 -0
  58. package/dist/renderers/last-price-renderer.js +46 -0
  59. package/dist/renderers/line-renderer.d.ts +23 -0
  60. package/dist/renderers/line-renderer.d.ts.map +1 -0
  61. package/dist/renderers/line-renderer.js +80 -0
  62. package/dist/renderers/line-with-markers-renderer.d.ts +13 -0
  63. package/dist/renderers/line-with-markers-renderer.d.ts.map +1 -0
  64. package/dist/renderers/line-with-markers-renderer.js +35 -0
  65. package/dist/renderers/marker-renderer.d.ts +16 -0
  66. package/dist/renderers/marker-renderer.d.ts.map +1 -0
  67. package/dist/renderers/marker-renderer.js +91 -0
  68. package/dist/renderers/mixed-renderer.d.ts +18 -0
  69. package/dist/renderers/mixed-renderer.d.ts.map +1 -0
  70. package/dist/renderers/mixed-renderer.js +123 -0
  71. package/dist/renderers/ohlc-bar-renderer.d.ts +21 -0
  72. package/dist/renderers/ohlc-bar-renderer.d.ts.map +1 -0
  73. package/dist/renderers/ohlc-bar-renderer.js +73 -0
  74. package/dist/renderers/pie-renderer.d.ts +26 -0
  75. package/dist/renderers/pie-renderer.d.ts.map +1 -0
  76. package/dist/renderers/pie-renderer.js +71 -0
  77. package/dist/renderers/polar-area-renderer.d.ts +13 -0
  78. package/dist/renderers/polar-area-renderer.d.ts.map +1 -0
  79. package/dist/renderers/polar-area-renderer.js +44 -0
  80. package/dist/renderers/radar-renderer.d.ts +16 -0
  81. package/dist/renderers/radar-renderer.d.ts.map +1 -0
  82. package/dist/renderers/radar-renderer.js +99 -0
  83. package/dist/renderers/scatter-renderer.d.ts +14 -0
  84. package/dist/renderers/scatter-renderer.d.ts.map +1 -0
  85. package/dist/renderers/scatter-renderer.js +42 -0
  86. package/dist/renderers/stacked-bar-renderer.d.ts +14 -0
  87. package/dist/renderers/stacked-bar-renderer.d.ts.map +1 -0
  88. package/dist/renderers/stacked-bar-renderer.js +52 -0
  89. package/dist/renderers/step-line-renderer.d.ts +19 -0
  90. package/dist/renderers/step-line-renderer.d.ts.map +1 -0
  91. package/dist/renderers/step-line-renderer.js +52 -0
  92. package/dist/renderers/supertrend-renderer.d.ts +18 -0
  93. package/dist/renderers/supertrend-renderer.d.ts.map +1 -0
  94. package/dist/renderers/supertrend-renderer.js +80 -0
  95. package/dist/renderers/volume-profile-renderer.d.ts +25 -0
  96. package/dist/renderers/volume-profile-renderer.d.ts.map +1 -0
  97. package/dist/renderers/volume-profile-renderer.js +83 -0
  98. package/dist/renderers/watermark-renderer.d.ts +15 -0
  99. package/dist/renderers/watermark-renderer.d.ts.map +1 -0
  100. package/dist/renderers/watermark-renderer.js +26 -0
  101. package/dist/scheduler.d.ts +25 -0
  102. package/dist/scheduler.d.ts.map +1 -0
  103. package/dist/scheduler.js +77 -0
  104. package/package.json +33 -4
@@ -0,0 +1 @@
1
+ {"version":3,"file":"grid-renderer.d.ts","sourceRoot":"","sources":["../../src/renderers/grid-renderer.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,SAAS,EAAE,SAAS,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,6BAA6B,CAAC;AAGpG,MAAM,WAAW,iBAAiB;IAChC,QAAQ,CAAC,GAAG,EAAE,wBAAwB,CAAC;IACvC,QAAQ,CAAC,MAAM,EAAE,SAAS,CAAC;IAC3B,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;IAC1B,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,cAAc,CAAC,EAAE,CAAC,CAAC,GAAG,EAAE,MAAM,KAAK,MAAM,CAAC,GAAG,SAAS,CAAC;IAChE,QAAQ,CAAC,cAAc,CAAC,EAAE,CAAC,CAAC,GAAG,EAAE,MAAM,KAAK,MAAM,CAAC,GAAG,SAAS,CAAC;IAChE,QAAQ,CAAC,SAAS,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;IACzC,QAAQ,CAAC,SAAS,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;IACzC,QAAQ,CAAC,SAAS,CAAC,EAAE,SAAS,GAAG,SAAS,CAAC;IAC3C,gFAAgF;IAChF,QAAQ,CAAC,aAAa,CAAC,EAAE,MAAM,GAAG,OAAO,GAAG,MAAM,GAAG,SAAS,CAAC;IAC/D,mDAAmD;IACnD,QAAQ,CAAC,eAAe,CAAC,EAAE,KAAK,CAAC,MAAM,CAAC,GAAG,SAAS,CAAC;IACrD,QAAQ,CAAC,uBAAuB,CAAC,EAAE,CAAC,CAAC,GAAG,EAAE,MAAM,KAAK,MAAM,CAAC,GAAG,SAAS,CAAC;CAC1E;AAED,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,iBAAiB,GAAG,IAAI,CA+HlE"}
@@ -0,0 +1,103 @@
1
+ /**
2
+ * @file packages/chart-renderer-canvas/src/renderers/grid-renderer.ts
3
+ * Crisp gridlines, axes, and tick text labels.
4
+ */
5
+ import { snapLine } from '../dpi.js';
6
+ export function renderGridAndAxes(options) {
7
+ const { ctx, bounds, padding, xScale, yScale, theme, dpr, xTickFormatter = (v) => v.toString(), yTickFormatter = (v) => v.toFixed(2), showXGrid = true, showYGrid = true, gridStyle = 'dashed', yAxisPosition = 'right', secondaryYScale, secondaryYTickFormatter = (v) => `${v.toFixed(1)}%`, } = options;
8
+ const left = padding.left;
9
+ const right = bounds.width - padding.right;
10
+ const top = padding.top;
11
+ const bottom = bounds.height - padding.bottom;
12
+ const getLineDash = (style) => {
13
+ switch (style) {
14
+ case 'solid':
15
+ return [];
16
+ case 'dotted':
17
+ return [1, 3];
18
+ case 'dashed':
19
+ default:
20
+ return [3, 3];
21
+ }
22
+ };
23
+ const lineDashPattern = getLineDash(gridStyle);
24
+ ctx.save();
25
+ // Primary Horizontal Grid Lines & Y-Axis Labels
26
+ const yTicks = yScale.ticks(6);
27
+ ctx.strokeStyle = theme.gridLine;
28
+ ctx.lineWidth = 1;
29
+ ctx.font = '10px monospace';
30
+ ctx.fillStyle = theme.textSecondary;
31
+ ctx.textBaseline = 'middle';
32
+ for (const tickVal of yTicks) {
33
+ const rawY = yScale.scale(tickVal);
34
+ if (rawY < top || rawY > bottom)
35
+ continue;
36
+ const y = snapLine(rawY, dpr);
37
+ if (showYGrid) {
38
+ ctx.beginPath();
39
+ ctx.setLineDash(lineDashPattern);
40
+ ctx.moveTo(left, y);
41
+ ctx.lineTo(right, y);
42
+ ctx.stroke();
43
+ }
44
+ const label = yTickFormatter(tickVal);
45
+ ctx.setLineDash([]);
46
+ if (yAxisPosition === 'left' || yAxisPosition === 'both') {
47
+ ctx.textAlign = 'right';
48
+ ctx.fillText(label, left - 6, y);
49
+ }
50
+ if (yAxisPosition === 'right' || (yAxisPosition === 'both' && !secondaryYScale)) {
51
+ ctx.textAlign = 'left';
52
+ ctx.fillText(label, right + 6, y);
53
+ }
54
+ }
55
+ // Secondary Y-Axis Labels (for Dual-Axis / Mixed Charts)
56
+ if (secondaryYScale && (yAxisPosition === 'both' || yAxisPosition === 'right')) {
57
+ const secTicks = secondaryYScale.ticks(6);
58
+ ctx.font = '10px monospace';
59
+ ctx.fillStyle = '#f59e0b'; // Distinct secondary indicator color
60
+ ctx.textAlign = 'left';
61
+ for (const tickVal of secTicks) {
62
+ const rawY = secondaryYScale.scale(tickVal);
63
+ if (rawY < top || rawY > bottom)
64
+ continue;
65
+ const y = snapLine(rawY, dpr);
66
+ const label = secondaryYTickFormatter(tickVal);
67
+ ctx.fillText(label, right + 6, y);
68
+ }
69
+ }
70
+ // Vertical Grid Lines & X-Axis Labels
71
+ const xTicks = xScale.ticks(6);
72
+ ctx.textAlign = 'center';
73
+ ctx.textBaseline = 'top';
74
+ for (const tickVal of xTicks) {
75
+ const rawX = xScale.scale(tickVal);
76
+ if (rawX < left || rawX > right)
77
+ continue;
78
+ const x = snapLine(rawX, dpr);
79
+ if (showXGrid) {
80
+ ctx.beginPath();
81
+ ctx.setLineDash(lineDashPattern);
82
+ ctx.moveTo(x, top);
83
+ ctx.lineTo(x, bottom);
84
+ ctx.stroke();
85
+ }
86
+ // X Axis Tick Label below the bottom axis
87
+ const label = xTickFormatter(tickVal);
88
+ ctx.setLineDash([]);
89
+ ctx.fillText(label, x, bottom + 6);
90
+ }
91
+ // Outer Plot Area Boundary
92
+ ctx.strokeStyle = theme.axisLine;
93
+ ctx.setLineDash([]);
94
+ ctx.beginPath();
95
+ // Bottom axis line
96
+ ctx.moveTo(left, snapLine(bottom, dpr));
97
+ ctx.lineTo(right, snapLine(bottom, dpr));
98
+ // Right axis line
99
+ ctx.moveTo(snapLine(right, dpr), top);
100
+ ctx.lineTo(snapLine(right, dpr), bottom);
101
+ ctx.stroke();
102
+ ctx.restore();
103
+ }
@@ -0,0 +1,16 @@
1
+ /**
2
+ * @file packages/chart-renderer-canvas/src/renderers/heatmap-renderer.ts
3
+ * High-performance 2D Matrix Heatmap renderer for correlation matrices, activity grids, and telemetry.
4
+ */
5
+ import type { Dimension, HeatmapDatum, Padding } from '@tranding-custom-chart/core';
6
+ export interface HeatmapRenderOptions {
7
+ readonly cellGap?: number | undefined;
8
+ readonly cellRadius?: number | undefined;
9
+ readonly colorLow?: string | undefined;
10
+ readonly colorHigh?: string | undefined;
11
+ readonly showLabels?: boolean | undefined;
12
+ readonly labelColor?: string | undefined;
13
+ readonly fontSize?: number | undefined;
14
+ }
15
+ export declare function renderHeatmap(ctx: CanvasRenderingContext2D, data: readonly HeatmapDatum[], bounds: Dimension, padding: Padding, options?: HeatmapRenderOptions): void;
16
+ //# sourceMappingURL=heatmap-renderer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"heatmap-renderer.d.ts","sourceRoot":"","sources":["../../src/renderers/heatmap-renderer.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,SAAS,EAAE,YAAY,EAAE,OAAO,EAAE,MAAM,6BAA6B,CAAC;AAEpF,MAAM,WAAW,oBAAoB;IACnC,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACtC,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACzC,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACvC,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACxC,QAAQ,CAAC,UAAU,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;IAC1C,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACzC,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CACxC;AAqBD,wBAAgB,aAAa,CAC3B,GAAG,EAAE,wBAAwB,EAC7B,IAAI,EAAE,SAAS,YAAY,EAAE,EAC7B,MAAM,EAAE,SAAS,EACjB,OAAO,EAAE,OAAO,EAChB,OAAO,GAAE,oBAAyB,GACjC,IAAI,CAyEN"}
@@ -0,0 +1,80 @@
1
+ /**
2
+ * @file packages/chart-renderer-canvas/src/renderers/heatmap-renderer.ts
3
+ * High-performance 2D Matrix Heatmap renderer for correlation matrices, activity grids, and telemetry.
4
+ */
5
+ function parseRgba(colorStr) {
6
+ if (colorStr.startsWith('#')) {
7
+ let hex = colorStr.slice(1);
8
+ if (hex.length === 3)
9
+ hex = hex.split('').map((c) => c + c).join('');
10
+ const num = parseInt(hex, 16);
11
+ return [(num >> 16) & 255, (num >> 8) & 255, num & 255, 1];
12
+ }
13
+ const match = colorStr.match(/rgba?\((\d+),\s*(\d+),\s*(\d+)(?:,\s*([\d.]+))?\)/);
14
+ if (match) {
15
+ return [
16
+ parseInt(match[1], 10),
17
+ parseInt(match[2], 10),
18
+ parseInt(match[3], 10),
19
+ match[4] !== undefined ? parseFloat(match[4]) : 1,
20
+ ];
21
+ }
22
+ return [59, 130, 246, 1];
23
+ }
24
+ export function renderHeatmap(ctx, data, bounds, padding, options = {}) {
25
+ if (data.length === 0)
26
+ return;
27
+ const { cellGap = 2, cellRadius = 2, colorLow = 'rgba(30, 41, 59, 0.6)', colorHigh = 'rgba(16, 185, 129, 0.9)', showLabels = false, labelColor = '#ffffff', fontSize = 10, } = options;
28
+ // Extract unique X categories (columns) and Y categories (rows)
29
+ const cols = Array.from(new Set(data.map((d) => String(d.x))));
30
+ const rows = Array.from(new Set(data.map((d) => String(d.y))));
31
+ if (cols.length === 0 || rows.length === 0)
32
+ return;
33
+ let minVal = Infinity;
34
+ let maxVal = -Infinity;
35
+ for (const d of data) {
36
+ if (d.value < minVal)
37
+ minVal = d.value;
38
+ if (d.value > maxVal)
39
+ maxVal = d.value;
40
+ }
41
+ const valRange = maxVal > minVal ? maxVal - minVal : 1;
42
+ const plotWidth = bounds.width - padding.left - padding.right;
43
+ const plotHeight = bounds.height - padding.top - padding.bottom;
44
+ const colWidth = (plotWidth - (cols.length - 1) * cellGap) / cols.length;
45
+ const rowHeight = (plotHeight - (rows.length - 1) * cellGap) / rows.length;
46
+ const [r1, g1, b1, a1] = parseRgba(colorLow);
47
+ const [r2, g2, b2, a2] = parseRgba(colorHigh);
48
+ ctx.save();
49
+ ctx.font = `${fontSize}px system-ui, sans-serif`;
50
+ ctx.textAlign = 'center';
51
+ ctx.textBaseline = 'middle';
52
+ for (const datum of data) {
53
+ const colIdx = cols.indexOf(String(datum.x));
54
+ const rowIdx = rows.indexOf(String(datum.y));
55
+ if (colIdx === -1 || rowIdx === -1)
56
+ continue;
57
+ const x = padding.left + colIdx * (colWidth + cellGap);
58
+ const y = padding.top + rowIdx * (rowHeight + cellGap);
59
+ const t = Math.max(0, Math.min(1, (datum.value - minVal) / valRange));
60
+ const r = Math.round(r1 + t * (r2 - r1));
61
+ const g = Math.round(g1 + t * (g2 - g1));
62
+ const b = Math.round(b1 + t * (b2 - b1));
63
+ const a = a1 + t * (a2 - a1);
64
+ ctx.fillStyle = `rgba(${r}, ${g}, ${b}, ${a})`;
65
+ if (cellRadius > 0 && typeof ctx.roundRect === 'function') {
66
+ ctx.beginPath();
67
+ ctx.roundRect(x, y, colWidth, rowHeight, cellRadius);
68
+ ctx.fill();
69
+ }
70
+ else {
71
+ ctx.fillRect(x, y, colWidth, rowHeight);
72
+ }
73
+ if (showLabels && colWidth > 20 && rowHeight > 14) {
74
+ ctx.fillStyle = labelColor;
75
+ const text = datum.label ?? (Number.isInteger(datum.value) ? String(datum.value) : datum.value.toFixed(1));
76
+ ctx.fillText(text, x + colWidth / 2, y + rowHeight / 2);
77
+ }
78
+ }
79
+ ctx.restore();
80
+ }
@@ -0,0 +1,19 @@
1
+ /**
2
+ * @file packages/chart-renderer-canvas/src/renderers/high-low-renderer.ts
3
+ * High-Low range bars renderer showing volatility and trading spread without open/close ticks.
4
+ */
5
+ import type { ChartTheme, OHLCVBar, Scale } from '@tranding-custom-chart/core';
6
+ export interface HighLowRenderOptions {
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 | undefined;
14
+ readonly endIndex?: number | undefined;
15
+ readonly customColor?: string | undefined;
16
+ readonly lineWidth?: number | undefined;
17
+ }
18
+ export declare function renderHighLowBars(options: HighLowRenderOptions): void;
19
+ //# sourceMappingURL=high-low-renderer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"high-low-renderer.d.ts","sourceRoot":"","sources":["../../src/renderers/high-low-renderer.ts"],"names":[],"mappings":"AAAA;;;GAGG;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,KAAK,EAAE,UAAU,CAAC;IAC3B,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACzC,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACvC,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC1C,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CACzC;AAED,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,oBAAoB,GAAG,IAAI,CAsCrE"}
@@ -0,0 +1,28 @@
1
+ /**
2
+ * @file packages/chart-renderer-canvas/src/renderers/high-low-renderer.ts
3
+ * High-Low range bars renderer showing volatility and trading spread without open/close ticks.
4
+ */
5
+ import { snapLine } from '../dpi.js';
6
+ export function renderHighLowBars(options) {
7
+ const { ctx, bars, xScale, yScale, theme, dpr, startIndex = 0, endIndex = bars.length - 1, customColor, lineWidth = 2, } = 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
+ const color = customColor ?? theme.accent;
13
+ const slotWidth = bars.length > 1 ? Math.abs(xScale.scale(1) - xScale.scale(0)) : 10;
14
+ ctx.save();
15
+ ctx.strokeStyle = color;
16
+ ctx.lineWidth = slotWidth < 2 ? 0.75 : lineWidth;
17
+ ctx.beginPath();
18
+ for (let i = start; i <= end; i++) {
19
+ const b = bars[i];
20
+ const x = snapLine(xScale.scale(i), dpr);
21
+ const yHigh = snapLine(yScale.scale(b.high), dpr);
22
+ const yLow = snapLine(yScale.scale(b.low), dpr);
23
+ ctx.moveTo(x, yHigh);
24
+ ctx.lineTo(x, yLow);
25
+ }
26
+ ctx.stroke();
27
+ ctx.restore();
28
+ }
@@ -0,0 +1,22 @@
1
+ /**
2
+ * @file packages/chart-renderer-canvas/src/renderers/hlc-area-renderer.ts
3
+ * Canvas 2D renderer for HLC Area charts.
4
+ * Fills the shaded vertical band between High and Low prices with a crisp Close line overlay.
5
+ */
6
+ import type { ChartTheme, OHLCVBar, Scale } from '@tranding-custom-chart/core';
7
+ export interface HlcAreaRenderOptions {
8
+ readonly ctx: CanvasRenderingContext2D;
9
+ readonly bars: readonly OHLCVBar[];
10
+ readonly xScale: Scale<number>;
11
+ readonly yScale: Scale<number>;
12
+ readonly theme?: ChartTheme | undefined;
13
+ readonly bandFillColor?: string | undefined;
14
+ readonly closeLineColor?: string | undefined;
15
+ readonly closeLineWidth?: number | undefined;
16
+ readonly highLineColor?: string | undefined;
17
+ readonly lowLineColor?: string | undefined;
18
+ readonly startIndex?: number | undefined;
19
+ readonly endIndex?: number | undefined;
20
+ }
21
+ export declare function renderHlcArea(options: HlcAreaRenderOptions): void;
22
+ //# sourceMappingURL=hlc-area-renderer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hlc-area-renderer.d.ts","sourceRoot":"","sources":["../../src/renderers/hlc-area-renderer.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,QAAQ,EAAE,KAAK,EAAE,MAAM,6BAA6B,CAAC;AAE/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,KAAK,CAAC,EAAE,UAAU,GAAG,SAAS,CAAC;IACxC,QAAQ,CAAC,aAAa,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC5C,QAAQ,CAAC,cAAc,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC7C,QAAQ,CAAC,cAAc,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC7C,QAAQ,CAAC,aAAa,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC5C,QAAQ,CAAC,YAAY,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC3C,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,CA6EjE"}
@@ -0,0 +1,72 @@
1
+ /**
2
+ * @file packages/chart-renderer-canvas/src/renderers/hlc-area-renderer.ts
3
+ * Canvas 2D renderer for HLC Area charts.
4
+ * Fills the shaded vertical band between High and Low prices with a crisp Close line overlay.
5
+ */
6
+ export function renderHlcArea(options) {
7
+ const { ctx, bars, xScale, yScale, bandFillColor = 'rgba(37, 99, 235, 0.18)', closeLineColor = '#2563eb', closeLineWidth = 2, highLineColor = 'rgba(37, 99, 235, 0.4)', lowLineColor = 'rgba(37, 99, 235, 0.4)', startIndex = 0, endIndex = bars.length - 1, } = options;
8
+ if (bars.length < 2 || startIndex > endIndex)
9
+ return;
10
+ const start = Math.max(0, startIndex);
11
+ const end = Math.min(bars.length - 1, endIndex);
12
+ ctx.save();
13
+ // 1. Draw High-Low Shaded Band
14
+ ctx.beginPath();
15
+ // Trace high forward
16
+ for (let i = start; i <= end; i++) {
17
+ const x = xScale.scale(i);
18
+ const yHigh = yScale.scale(bars[i].high);
19
+ if (i === start)
20
+ ctx.moveTo(x, yHigh);
21
+ else
22
+ ctx.lineTo(x, yHigh);
23
+ }
24
+ // Trace low backward
25
+ for (let i = end; i >= start; i--) {
26
+ const x = xScale.scale(i);
27
+ const yLow = yScale.scale(bars[i].low);
28
+ ctx.lineTo(x, yLow);
29
+ }
30
+ ctx.closePath();
31
+ ctx.fillStyle = bandFillColor;
32
+ ctx.fill();
33
+ // 2. High & Low Boundary Lines (subtle)
34
+ ctx.beginPath();
35
+ for (let i = start; i <= end; i++) {
36
+ const x = xScale.scale(i);
37
+ const y = yScale.scale(bars[i].high);
38
+ if (i === start)
39
+ ctx.moveTo(x, y);
40
+ else
41
+ ctx.lineTo(x, y);
42
+ }
43
+ ctx.strokeStyle = highLineColor;
44
+ ctx.lineWidth = 1;
45
+ ctx.stroke();
46
+ ctx.beginPath();
47
+ for (let i = start; i <= end; i++) {
48
+ const x = xScale.scale(i);
49
+ const y = yScale.scale(bars[i].low);
50
+ if (i === start)
51
+ ctx.moveTo(x, y);
52
+ else
53
+ ctx.lineTo(x, y);
54
+ }
55
+ ctx.strokeStyle = lowLineColor;
56
+ ctx.lineWidth = 1;
57
+ ctx.stroke();
58
+ // 3. Close Price Line
59
+ ctx.beginPath();
60
+ for (let i = start; i <= end; i++) {
61
+ const x = xScale.scale(i);
62
+ const y = yScale.scale(bars[i].close);
63
+ if (i === start)
64
+ ctx.moveTo(x, y);
65
+ else
66
+ ctx.lineTo(x, y);
67
+ }
68
+ ctx.strokeStyle = closeLineColor;
69
+ ctx.lineWidth = closeLineWidth;
70
+ ctx.stroke();
71
+ ctx.restore();
72
+ }
@@ -0,0 +1,26 @@
1
+ /**
2
+ * @file packages/chart-renderer-canvas/src/renderers/hollow-candlestick-renderer.ts
3
+ * Hollow candlestick renderer representing both intraday and bar-to-bar price direction.
4
+ *
5
+ * Rules:
6
+ * - Close >= Open: Hollow body (stroked outline)
7
+ * - Close < Open: Solid body (filled interior)
8
+ * - Close >= PrevClose: Bullish Green color
9
+ * - Close < PrevClose: Bearish Red color
10
+ */
11
+ import type { ChartTheme, OHLCVBar, Scale } from '@tranding-custom-chart/core';
12
+ export interface HollowCandlestickRenderOptions {
13
+ readonly ctx: CanvasRenderingContext2D;
14
+ readonly bars: readonly OHLCVBar[];
15
+ readonly xScale: Scale<number>;
16
+ readonly yScale: Scale<number>;
17
+ readonly theme: ChartTheme;
18
+ readonly dpr: number;
19
+ readonly startIndex?: number | undefined;
20
+ readonly endIndex?: number | undefined;
21
+ readonly candleWidthRatio?: number | undefined;
22
+ readonly customUpColor?: string | undefined;
23
+ readonly customDownColor?: string | undefined;
24
+ }
25
+ export declare function renderHollowCandlesticks(options: HollowCandlestickRenderOptions): void;
26
+ //# sourceMappingURL=hollow-candlestick-renderer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hollow-candlestick-renderer.d.ts","sourceRoot":"","sources":["../../src/renderers/hollow-candlestick-renderer.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,QAAQ,EAAE,KAAK,EAAE,MAAM,6BAA6B,CAAC;AAG/E,MAAM,WAAW,8BAA8B;IAC7C,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,GAAG,SAAS,CAAC;IACzC,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACvC,QAAQ,CAAC,gBAAgB,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC/C,QAAQ,CAAC,aAAa,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC5C,QAAQ,CAAC,eAAe,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CAC/C;AAED,wBAAgB,wBAAwB,CAAC,OAAO,EAAE,8BAA8B,GAAG,IAAI,CAiFtF"}
@@ -0,0 +1,71 @@
1
+ /**
2
+ * @file packages/chart-renderer-canvas/src/renderers/hollow-candlestick-renderer.ts
3
+ * Hollow candlestick renderer representing both intraday and bar-to-bar price direction.
4
+ *
5
+ * Rules:
6
+ * - Close >= Open: Hollow body (stroked outline)
7
+ * - Close < Open: Solid body (filled interior)
8
+ * - Close >= PrevClose: Bullish Green color
9
+ * - Close < PrevClose: Bearish Red color
10
+ */
11
+ import { snapLine, snapRect } from '../dpi.js';
12
+ export function renderHollowCandlesticks(options) {
13
+ const { ctx, bars, xScale, yScale, theme, dpr, startIndex = 0, endIndex = bars.length - 1, candleWidthRatio = 0.7, customUpColor, customDownColor, } = options;
14
+ if (bars.length === 0 || startIndex > endIndex)
15
+ return;
16
+ const start = Math.max(0, startIndex);
17
+ const end = Math.min(bars.length - 1, endIndex);
18
+ let slotWidth = 8;
19
+ if ('stepWidth' in xScale && typeof xScale.stepWidth === 'number') {
20
+ slotWidth = xScale.stepWidth;
21
+ }
22
+ else if (bars.length > 1) {
23
+ const x0 = xScale.scale(0);
24
+ const x1 = xScale.scale(1);
25
+ slotWidth = Math.abs(x1 - x0) || 8;
26
+ }
27
+ const candleWidth = slotWidth < 2 ? Math.max(0.5, slotWidth * 0.8) : Math.max(1, slotWidth * candleWidthRatio);
28
+ const halfWidth = candleWidth / 2;
29
+ const upColor = customUpColor ?? theme.upCandle;
30
+ const downColor = customDownColor ?? theme.downCandle;
31
+ ctx.save();
32
+ ctx.lineWidth = slotWidth < 2 ? 0.75 : 1;
33
+ for (let i = start; i <= end; i++) {
34
+ const b = bars[i];
35
+ const prevClose = i > 0 ? bars[i - 1].close : b.open;
36
+ // Color determined by comparison with previous close
37
+ const isBullishColor = b.close >= prevClose;
38
+ const color = isBullishColor ? upColor : downColor;
39
+ const isHollow = b.close >= b.open;
40
+ const xCenter = snapLine(xScale.scale(i), dpr);
41
+ const yHigh = snapLine(yScale.scale(b.high), dpr);
42
+ const yLow = snapLine(yScale.scale(b.low), dpr);
43
+ const yOpen = yScale.scale(b.open);
44
+ const yClose = yScale.scale(b.close);
45
+ const bodyTop = snapRect(Math.min(yOpen, yClose), dpr);
46
+ const bodyBottom = snapRect(Math.max(yOpen, yClose), dpr);
47
+ const bodyHeight = Math.max(1, bodyBottom - bodyTop);
48
+ const bodyLeft = snapRect(xCenter - halfWidth, dpr);
49
+ ctx.strokeStyle = color;
50
+ ctx.fillStyle = color;
51
+ // Draw wicks
52
+ ctx.beginPath();
53
+ // Top wick: High to top of body
54
+ ctx.moveTo(xCenter, yHigh);
55
+ ctx.lineTo(xCenter, bodyTop);
56
+ // Bottom wick: Bottom of body to Low
57
+ ctx.moveTo(xCenter, bodyBottom);
58
+ ctx.lineTo(xCenter, yLow);
59
+ ctx.stroke();
60
+ // Draw body
61
+ if (isHollow) {
62
+ // Hollow body: clear interior to canvas background or fill with surface, stroke border
63
+ ctx.strokeRect(bodyLeft, bodyTop, candleWidth, bodyHeight);
64
+ }
65
+ else {
66
+ // Solid filled body
67
+ ctx.fillRect(bodyLeft, bodyTop, candleWidth, bodyHeight);
68
+ }
69
+ }
70
+ ctx.restore();
71
+ }
@@ -0,0 +1,25 @@
1
+ /**
2
+ * @file packages/chart-renderer-canvas/src/renderers/horizontal-bar-renderer.ts
3
+ * Canvas 2D renderer for Horizontal Bar charts with rounded corners and value badges.
4
+ */
5
+ import type { HorizontalBarDatum, Scale } from '@tranding-custom-chart/core';
6
+ export interface HorizontalBarOptions {
7
+ readonly bounds: {
8
+ readonly width: number;
9
+ readonly height: number;
10
+ };
11
+ readonly padding: {
12
+ readonly top: number;
13
+ readonly right: number;
14
+ readonly bottom: number;
15
+ readonly left: number;
16
+ };
17
+ readonly xScale: Scale<number>;
18
+ readonly barHeightRatio?: number | undefined;
19
+ readonly borderRadius?: number | undefined;
20
+ readonly defaultColor?: string | undefined;
21
+ readonly showLabels?: boolean | undefined;
22
+ readonly labelColor?: string | undefined;
23
+ }
24
+ export declare function renderHorizontalBars(ctx: CanvasRenderingContext2D, data: readonly HorizontalBarDatum[], options: HorizontalBarOptions): void;
25
+ //# sourceMappingURL=horizontal-bar-renderer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"horizontal-bar-renderer.d.ts","sourceRoot":"","sources":["../../src/renderers/horizontal-bar-renderer.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,kBAAkB,EAAE,KAAK,EAAE,MAAM,6BAA6B,CAAC;AAG7E,MAAM,WAAW,oBAAoB;IACnC,QAAQ,CAAC,MAAM,EAAE;QAAE,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC;IACrE,QAAQ,CAAC,OAAO,EAAE;QAAE,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC;IACnH,QAAQ,CAAC,MAAM,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC;IAC/B,QAAQ,CAAC,cAAc,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC7C,QAAQ,CAAC,YAAY,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC3C,QAAQ,CAAC,YAAY,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC3C,QAAQ,CAAC,UAAU,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;IAC1C,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CAC1C;AAED,wBAAgB,oBAAoB,CAClC,GAAG,EAAE,wBAAwB,EAC7B,IAAI,EAAE,SAAS,kBAAkB,EAAE,EACnC,OAAO,EAAE,oBAAoB,GAC5B,IAAI,CA6DN"}
@@ -0,0 +1,52 @@
1
+ /**
2
+ * @file packages/chart-renderer-canvas/src/renderers/horizontal-bar-renderer.ts
3
+ * Canvas 2D renderer for Horizontal Bar charts with rounded corners and value badges.
4
+ */
5
+ import { snapRect } from '../dpi.js';
6
+ export function renderHorizontalBars(ctx, data, options) {
7
+ if (data.length === 0)
8
+ return;
9
+ const { bounds, padding, xScale, barHeightRatio = 0.6, borderRadius = 4, defaultColor = '#3b82f6', showLabels = true, labelColor = '#e8ebe6', } = options;
10
+ const innerHeight = bounds.height - padding.top - padding.bottom;
11
+ const slotHeight = innerHeight / data.length;
12
+ const barHeight = Math.max(4, Math.round(slotHeight * barHeightRatio));
13
+ const zeroX = xScale.scale(0);
14
+ ctx.save();
15
+ for (let i = 0; i < data.length; i++) {
16
+ const item = data[i];
17
+ const slotY = padding.top + i * slotHeight;
18
+ const centerY = slotY + slotHeight / 2;
19
+ const top = centerY - barHeight / 2;
20
+ const valX = xScale.scale(item.value);
21
+ const left = Math.min(zeroX, valX);
22
+ const width = Math.max(2, Math.abs(valX - zeroX));
23
+ const rx = snapRect(left);
24
+ const ry = snapRect(top);
25
+ const rw = snapRect(width);
26
+ const rh = snapRect(barHeight);
27
+ ctx.fillStyle = item.color ?? defaultColor;
28
+ ctx.beginPath();
29
+ if (typeof ctx.roundRect === 'function' && borderRadius > 0) {
30
+ ctx.roundRect(rx, ry, rw, rh, Math.min(borderRadius, rh / 2));
31
+ }
32
+ else {
33
+ ctx.rect(rx, ry, rw, rh);
34
+ }
35
+ ctx.fill();
36
+ if (showLabels) {
37
+ // Category label on the left margin
38
+ ctx.fillStyle = labelColor;
39
+ const fontSize = slotHeight < 22 ? 10 : slotHeight < 28 ? 11 : 12;
40
+ ctx.font = `500 ${fontSize}px Inter, system-ui, sans-serif`;
41
+ ctx.textAlign = 'right';
42
+ ctx.textBaseline = 'middle';
43
+ ctx.fillText(item.category, rx - 8, centerY);
44
+ // Value label to the right of the bar
45
+ ctx.textAlign = 'left';
46
+ ctx.fillStyle = labelColor;
47
+ const displayVal = item.label ?? item.value.toLocaleString();
48
+ ctx.fillText(displayVal, rx + rw + 8, centerY);
49
+ }
50
+ }
51
+ ctx.restore();
52
+ }
@@ -0,0 +1,17 @@
1
+ /**
2
+ * @file packages/chart-renderer-canvas/src/renderers/last-price-renderer.ts
3
+ * Real-time last price line and dynamic Y-axis price badge.
4
+ */
5
+ import type { Dimension, Padding, Scale } from '@tranding-custom-chart/core';
6
+ export interface LastPriceRenderOptions {
7
+ readonly ctx: CanvasRenderingContext2D;
8
+ readonly lastPrice: number;
9
+ readonly yScale: Scale<number>;
10
+ readonly bounds: Dimension;
11
+ readonly padding: Padding;
12
+ readonly dpr: number;
13
+ readonly color?: string | undefined;
14
+ readonly formatter?: ((price: number) => string) | undefined;
15
+ }
16
+ export declare function renderLastPriceLine(options: LastPriceRenderOptions): void;
17
+ //# sourceMappingURL=last-price-renderer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"last-price-renderer.d.ts","sourceRoot":"","sources":["../../src/renderers/last-price-renderer.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,SAAS,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,6BAA6B,CAAC;AAG7E,MAAM,WAAW,sBAAsB;IACrC,QAAQ,CAAC,GAAG,EAAE,wBAAwB,CAAC;IACvC,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,MAAM,EAAE,KAAK,CAAC,MAAM,CAAC,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,KAAK,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACpC,QAAQ,CAAC,SAAS,CAAC,EAAE,CAAC,CAAC,KAAK,EAAE,MAAM,KAAK,MAAM,CAAC,GAAG,SAAS,CAAC;CAC9D;AAED,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,sBAAsB,GAAG,IAAI,CAyDzE"}
@@ -0,0 +1,46 @@
1
+ /**
2
+ * @file packages/chart-renderer-canvas/src/renderers/last-price-renderer.ts
3
+ * Real-time last price line and dynamic Y-axis price badge.
4
+ */
5
+ import { snapLine } from '../dpi.js';
6
+ export function renderLastPriceLine(options) {
7
+ const { ctx, lastPrice, yScale, bounds, padding, dpr, color = '#10b981', formatter = (p) => `₹${p.toFixed(2)}`, } = options;
8
+ if (!Number.isFinite(lastPrice))
9
+ return;
10
+ const yRaw = yScale.scale(lastPrice);
11
+ const chartTop = padding.top;
12
+ const chartBottom = bounds.height - padding.bottom;
13
+ // Do not draw if outside visible Y range
14
+ if (yRaw < chartTop || yRaw > chartBottom)
15
+ return;
16
+ const y = snapLine(yRaw, dpr);
17
+ const chartLeft = padding.left;
18
+ const chartRight = bounds.width - padding.right;
19
+ ctx.save();
20
+ // 1. Horizontal dashed line across chart
21
+ ctx.strokeStyle = color;
22
+ ctx.lineWidth = 1;
23
+ ctx.setLineDash([3, 3]);
24
+ ctx.beginPath();
25
+ ctx.moveTo(chartLeft, y);
26
+ ctx.lineTo(chartRight, y);
27
+ ctx.stroke();
28
+ // 2. Solid Price Badge on Right Y-Axis
29
+ ctx.setLineDash([]);
30
+ const text = formatter(lastPrice);
31
+ ctx.font = '10px monospace';
32
+ const textMetrics = ctx.measureText(text);
33
+ const badgeWidth = textMetrics.width + 10;
34
+ const badgeHeight = 16;
35
+ const badgeX = chartRight + 2;
36
+ const badgeY = y - badgeHeight / 2;
37
+ // Background rect
38
+ ctx.fillStyle = color;
39
+ ctx.fillRect(badgeX, badgeY, badgeWidth, badgeHeight);
40
+ // Text
41
+ ctx.fillStyle = '#ffffff';
42
+ ctx.textAlign = 'left';
43
+ ctx.textBaseline = 'middle';
44
+ ctx.fillText(text, badgeX + 5, y);
45
+ ctx.restore();
46
+ }
@@ -0,0 +1,23 @@
1
+ /**
2
+ * @file packages/chart-renderer-canvas/src/renderers/line-renderer.ts
3
+ * Stroked line and gradient area fill renderer.
4
+ */
5
+ import type { Scale } from '@tranding-custom-chart/core';
6
+ export interface LineRenderOptions {
7
+ readonly ctx: CanvasRenderingContext2D;
8
+ readonly points: readonly (number | null | undefined)[];
9
+ readonly xScale: Scale<number>;
10
+ readonly yScale: Scale<number>;
11
+ readonly color: string;
12
+ readonly strokeWidth?: number | undefined;
13
+ readonly lineDash?: readonly number[] | undefined;
14
+ readonly areaFill?: {
15
+ readonly gradientTopColor: string;
16
+ readonly gradientBottomColor: string;
17
+ readonly baselineY: number;
18
+ } | undefined;
19
+ readonly startIndex?: number | undefined;
20
+ readonly endIndex?: number | undefined;
21
+ }
22
+ export declare function renderLineSeries(options: LineRenderOptions): void;
23
+ //# sourceMappingURL=line-renderer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"line-renderer.d.ts","sourceRoot":"","sources":["../../src/renderers/line-renderer.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,6BAA6B,CAAC;AAEzD,MAAM,WAAW,iBAAiB;IAChC,QAAQ,CAAC,GAAG,EAAE,wBAAwB,CAAC;IACvC,QAAQ,CAAC,MAAM,EAAE,SAAS,CAAC,MAAM,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,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC1C,QAAQ,CAAC,QAAQ,CAAC,EAAE,SAAS,MAAM,EAAE,GAAG,SAAS,CAAC;IAClD,QAAQ,CAAC,QAAQ,CAAC,EAAE;QAClB,QAAQ,CAAC,gBAAgB,EAAE,MAAM,CAAC;QAClC,QAAQ,CAAC,mBAAmB,EAAE,MAAM,CAAC;QACrC,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;KAC5B,GAAG,SAAS,CAAC;IACd,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACzC,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CACxC;AAED,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,iBAAiB,GAAG,IAAI,CAiGjE"}