@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,16 @@
1
+ /**
2
+ * @file packages/chart-renderer-canvas/src/renderers/radar-renderer.ts
3
+ * Canvas 2D renderer for Radar / Spider charts with multi-axis circular web layout.
4
+ */
5
+ import type { RadarAxis, RadarDataset } from '@tranding-custom-chart/core';
6
+ export interface RadarRenderOptions {
7
+ readonly cx: number;
8
+ readonly cy: number;
9
+ readonly radius: number;
10
+ readonly rings?: number | undefined;
11
+ readonly gridColor?: string | undefined;
12
+ readonly axisColor?: string | undefined;
13
+ readonly labelColor?: string | undefined;
14
+ }
15
+ export declare function renderRadar(ctx: CanvasRenderingContext2D, axes: readonly RadarAxis[], datasets: readonly RadarDataset[], options: RadarRenderOptions): void;
16
+ //# sourceMappingURL=radar-renderer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"radar-renderer.d.ts","sourceRoot":"","sources":["../../src/renderers/radar-renderer.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,SAAS,EAAE,YAAY,EAAE,MAAM,6BAA6B,CAAC;AAE3E,MAAM,WAAW,kBAAkB;IACjC,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACpC,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACxC,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACxC,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CAC1C;AAED,wBAAgB,WAAW,CACzB,GAAG,EAAE,wBAAwB,EAC7B,IAAI,EAAE,SAAS,SAAS,EAAE,EAC1B,QAAQ,EAAE,SAAS,YAAY,EAAE,EACjC,OAAO,EAAE,kBAAkB,GAC1B,IAAI,CAmHN"}
@@ -0,0 +1,99 @@
1
+ /**
2
+ * @file packages/chart-renderer-canvas/src/renderers/radar-renderer.ts
3
+ * Canvas 2D renderer for Radar / Spider charts with multi-axis circular web layout.
4
+ */
5
+ export function renderRadar(ctx, axes, datasets, options) {
6
+ const n = axes.length;
7
+ if (n < 3 || options.radius <= 0)
8
+ return;
9
+ const { cx, cy, radius, rings = 4, gridColor = 'rgba(255, 255, 255, 0.12)', axisColor = 'rgba(255, 255, 255, 0.2)', labelColor = '#858e89', } = options;
10
+ const angleStep = (2 * Math.PI) / n;
11
+ const startAngle = -Math.PI / 2;
12
+ ctx.save();
13
+ // 1. Concentric Web Rings
14
+ ctx.strokeStyle = gridColor;
15
+ ctx.lineWidth = 1;
16
+ for (let r = 1; r <= rings; r++) {
17
+ const ringRadius = (radius * r) / rings;
18
+ ctx.beginPath();
19
+ for (let i = 0; i < n; i++) {
20
+ const angle = startAngle + i * angleStep;
21
+ const x = cx + Math.cos(angle) * ringRadius;
22
+ const y = cy + Math.sin(angle) * ringRadius;
23
+ if (i === 0)
24
+ ctx.moveTo(x, y);
25
+ else
26
+ ctx.lineTo(x, y);
27
+ }
28
+ ctx.closePath();
29
+ ctx.stroke();
30
+ }
31
+ // 2. Spoke Lines and Axis Labels
32
+ ctx.strokeStyle = axisColor;
33
+ ctx.fillStyle = labelColor;
34
+ ctx.font = '500 11px Inter, system-ui, sans-serif';
35
+ ctx.textBaseline = 'middle';
36
+ for (let i = 0; i < n; i++) {
37
+ const axis = axes[i];
38
+ const angle = startAngle + i * angleStep;
39
+ const endX = cx + Math.cos(angle) * radius;
40
+ const endY = cy + Math.sin(angle) * radius;
41
+ // Spoke Line
42
+ ctx.beginPath();
43
+ ctx.moveTo(cx, cy);
44
+ ctx.lineTo(endX, endY);
45
+ ctx.stroke();
46
+ // Axis Label
47
+ const labelDistance = radius + 14;
48
+ const labelX = cx + Math.cos(angle) * labelDistance;
49
+ const labelY = cy + Math.sin(angle) * labelDistance;
50
+ const cos = Math.cos(angle);
51
+ if (Math.abs(cos) < 0.1) {
52
+ ctx.textAlign = 'center';
53
+ }
54
+ else if (cos > 0) {
55
+ ctx.textAlign = 'left';
56
+ }
57
+ else {
58
+ ctx.textAlign = 'right';
59
+ }
60
+ ctx.fillText(axis.label, labelX, labelY);
61
+ }
62
+ // 3. Datasets Filled Polygons
63
+ for (const ds of datasets) {
64
+ const points = [];
65
+ for (let i = 0; i < n; i++) {
66
+ const axis = axes[i];
67
+ const val = ds.data[axis.key] ?? 0;
68
+ const ratio = Math.max(0, Math.min(1.0, axis.max > 0 ? val / axis.max : 0));
69
+ const ptRadius = radius * ratio;
70
+ const angle = startAngle + i * angleStep;
71
+ points.push({
72
+ x: cx + Math.cos(angle) * ptRadius,
73
+ y: cy + Math.sin(angle) * ptRadius,
74
+ });
75
+ }
76
+ if (points.length < 3)
77
+ continue;
78
+ // Fill polygon
79
+ ctx.beginPath();
80
+ ctx.moveTo(points[0].x, points[0].y);
81
+ for (let i = 1; i < points.length; i++) {
82
+ ctx.lineTo(points[i].x, points[i].y);
83
+ }
84
+ ctx.closePath();
85
+ ctx.fillStyle = ds.fillColor;
86
+ ctx.fill();
87
+ ctx.lineWidth = ds.strokeWidth ?? 2;
88
+ ctx.strokeStyle = ds.strokeColor;
89
+ ctx.stroke();
90
+ // Node markers
91
+ ctx.fillStyle = ds.strokeColor;
92
+ for (const pt of points) {
93
+ ctx.beginPath();
94
+ ctx.arc(pt.x, pt.y, 3, 0, 2 * Math.PI);
95
+ ctx.fill();
96
+ }
97
+ }
98
+ ctx.restore();
99
+ }
@@ -0,0 +1,14 @@
1
+ /**
2
+ * @file packages/chart-renderer-canvas/src/renderers/scatter-renderer.ts
3
+ * High-performance 2D Canvas renderer for Scatter Plots.
4
+ */
5
+ import type { Scale, ScatterDatum } from '@tranding-custom-chart/core';
6
+ export interface ScatterRenderOptions {
7
+ readonly defaultRadius?: number;
8
+ readonly defaultColor?: string;
9
+ readonly strokeColor?: string;
10
+ readonly strokeWidth?: number;
11
+ readonly shape?: 'circle' | 'square' | 'triangle';
12
+ }
13
+ export declare function renderScatter(ctx: CanvasRenderingContext2D, data: readonly ScatterDatum[], xScale: Scale<number>, yScale: Scale<number>, options?: ScatterRenderOptions): void;
14
+ //# sourceMappingURL=scatter-renderer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scatter-renderer.d.ts","sourceRoot":"","sources":["../../src/renderers/scatter-renderer.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,KAAK,EAAE,YAAY,EAAE,MAAM,6BAA6B,CAAC;AAEvE,MAAM,WAAW,oBAAoB;IACnC,QAAQ,CAAC,aAAa,CAAC,EAAE,MAAM,CAAC;IAChC,QAAQ,CAAC,YAAY,CAAC,EAAE,MAAM,CAAC;IAC/B,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,KAAK,CAAC,EAAE,QAAQ,GAAG,QAAQ,GAAG,UAAU,CAAC;CACnD;AAED,wBAAgB,aAAa,CAC3B,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,CAyCN"}
@@ -0,0 +1,42 @@
1
+ /**
2
+ * @file packages/chart-renderer-canvas/src/renderers/scatter-renderer.ts
3
+ * High-performance 2D Canvas renderer for Scatter Plots.
4
+ */
5
+ export function renderScatter(ctx, data, xScale, yScale, options = {}) {
6
+ if (!data || data.length === 0)
7
+ return;
8
+ const defaultRadius = options.defaultRadius ?? 4;
9
+ const defaultColor = options.defaultColor ?? '#3b82f6';
10
+ const strokeColor = options.strokeColor ?? '#ffffff';
11
+ const strokeWidth = options.strokeWidth ?? 1.5;
12
+ ctx.save();
13
+ ctx.lineWidth = strokeWidth;
14
+ for (let i = 0; i < data.length; i++) {
15
+ const d = data[i];
16
+ const px = xScale.scale(d.x);
17
+ const py = yScale.scale(d.y);
18
+ const r = d.radius ?? defaultRadius;
19
+ const color = d.color ?? defaultColor;
20
+ const shape = d.shape ?? options.shape ?? 'circle';
21
+ ctx.fillStyle = color;
22
+ ctx.strokeStyle = strokeColor;
23
+ ctx.beginPath();
24
+ if (shape === 'square') {
25
+ ctx.rect(px - r, py - r, r * 2, r * 2);
26
+ }
27
+ else if (shape === 'triangle') {
28
+ ctx.moveTo(px, py - r * 1.2);
29
+ ctx.lineTo(px + r, py + r * 0.8);
30
+ ctx.lineTo(px - r, py + r * 0.8);
31
+ ctx.closePath();
32
+ }
33
+ else {
34
+ ctx.arc(px, py, r, 0, Math.PI * 2);
35
+ }
36
+ ctx.fill();
37
+ if (strokeWidth > 0) {
38
+ ctx.stroke();
39
+ }
40
+ }
41
+ ctx.restore();
42
+ }
@@ -0,0 +1,14 @@
1
+ /**
2
+ * @file packages/chart-renderer-canvas/src/renderers/stacked-bar-renderer.ts
3
+ * Canvas 2D renderer for Stacked Bar charts with cumulative height calculations.
4
+ */
5
+ import type { StackedBarDatum, Scale } from '@tranding-custom-chart/core';
6
+ export interface StackedBarOptions {
7
+ readonly xScale: Scale<number>;
8
+ readonly yScale: Scale<number>;
9
+ readonly columnWidthRatio?: number | undefined;
10
+ readonly defaultColors?: readonly string[] | undefined;
11
+ readonly borderRadius?: number | undefined;
12
+ }
13
+ export declare function renderStackedBars(ctx: CanvasRenderingContext2D, data: readonly StackedBarDatum[], options: StackedBarOptions): void;
14
+ //# sourceMappingURL=stacked-bar-renderer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"stacked-bar-renderer.d.ts","sourceRoot":"","sources":["../../src/renderers/stacked-bar-renderer.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,eAAe,EAAE,KAAK,EAAE,MAAM,6BAA6B,CAAC;AAG1E,MAAM,WAAW,iBAAiB;IAChC,QAAQ,CAAC,MAAM,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC;IAC/B,QAAQ,CAAC,MAAM,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC;IAC/B,QAAQ,CAAC,gBAAgB,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC/C,QAAQ,CAAC,aAAa,CAAC,EAAE,SAAS,MAAM,EAAE,GAAG,SAAS,CAAC;IACvD,QAAQ,CAAC,YAAY,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CAC5C;AAED,wBAAgB,iBAAiB,CAC/B,GAAG,EAAE,wBAAwB,EAC7B,IAAI,EAAE,SAAS,eAAe,EAAE,EAChC,OAAO,EAAE,iBAAiB,GACzB,IAAI,CAyDN"}
@@ -0,0 +1,52 @@
1
+ /**
2
+ * @file packages/chart-renderer-canvas/src/renderers/stacked-bar-renderer.ts
3
+ * Canvas 2D renderer for Stacked Bar charts with cumulative height calculations.
4
+ */
5
+ import { snapRect } from '../dpi.js';
6
+ export function renderStackedBars(ctx, data, options) {
7
+ if (data.length === 0)
8
+ return;
9
+ const { xScale, yScale, columnWidthRatio = 0.6, defaultColors = ['#10b981', '#3b82f6', '#f59e0b', '#ec4899'], borderRadius = 4, } = options;
10
+ const x0 = xScale.scale(0);
11
+ const x1 = data.length > 1 ? xScale.scale(1) : x0 + 20;
12
+ const slotWidth = Math.max(6, Math.abs(x1 - x0));
13
+ const colWidth = Math.max(4, Math.round(slotWidth * columnWidthRatio));
14
+ ctx.save();
15
+ for (let i = 0; i < data.length; i++) {
16
+ const datum = data[i];
17
+ const cx = xScale.scale(i);
18
+ const left = cx - colWidth / 2;
19
+ const colors = datum.colors ?? defaultColors;
20
+ let cumulativeValue = 0;
21
+ const count = datum.values.length;
22
+ for (let s = 0; s < count; s++) {
23
+ const val = Math.max(0, datum.values[s] ?? 0);
24
+ const prevY = yScale.scale(cumulativeValue);
25
+ cumulativeValue += val;
26
+ const nextY = yScale.scale(cumulativeValue);
27
+ const top = Math.min(prevY, nextY);
28
+ const height = Math.abs(prevY - nextY);
29
+ if (height <= 0)
30
+ continue;
31
+ const rx = snapRect(left);
32
+ const ry = snapRect(top);
33
+ const rw = snapRect(colWidth);
34
+ const rh = snapRect(height);
35
+ ctx.fillStyle = colors[s % colors.length] ?? '#3b82f6';
36
+ ctx.beginPath();
37
+ const isTopSegment = s === count - 1;
38
+ if (isTopSegment && borderRadius > 0 && typeof ctx.roundRect === 'function') {
39
+ // Round only the top corners of the topmost segment
40
+ ctx.roundRect(rx, ry, rw, rh, [borderRadius, borderRadius, 0, 0]);
41
+ }
42
+ else if (typeof ctx.rect === 'function') {
43
+ ctx.rect(rx, ry, rw, rh);
44
+ }
45
+ else {
46
+ ctx.fillRect(rx, ry, rw, rh);
47
+ }
48
+ ctx.fill();
49
+ }
50
+ }
51
+ ctx.restore();
52
+ }
@@ -0,0 +1,19 @@
1
+ /**
2
+ * @file packages/chart-renderer-canvas/src/renderers/step-line-renderer.ts
3
+ * Step line (staircase) series renderer.
4
+ */
5
+ import type { Scale } from '@tranding-custom-chart/core';
6
+ export interface StepLineRenderOptions {
7
+ readonly ctx: CanvasRenderingContext2D;
8
+ readonly data: readonly (number | null)[];
9
+ readonly xScale: Scale<number>;
10
+ readonly yScale: Scale<number>;
11
+ readonly color?: string | undefined;
12
+ readonly strokeWidth?: number | undefined;
13
+ readonly areaFill?: {
14
+ readonly baselineY: number;
15
+ readonly fillColor: string;
16
+ } | undefined;
17
+ }
18
+ export declare function renderStepLine(options: StepLineRenderOptions): void;
19
+ //# sourceMappingURL=step-line-renderer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"step-line-renderer.d.ts","sourceRoot":"","sources":["../../src/renderers/step-line-renderer.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,6BAA6B,CAAC;AAEzD,MAAM,WAAW,qBAAqB;IACpC,QAAQ,CAAC,GAAG,EAAE,wBAAwB,CAAC;IACvC,QAAQ,CAAC,IAAI,EAAE,SAAS,CAAC,MAAM,GAAG,IAAI,CAAC,EAAE,CAAC;IAC1C,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,MAAM,GAAG,SAAS,CAAC;IACpC,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC1C,QAAQ,CAAC,QAAQ,CAAC,EAAE;QAClB,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;QAC3B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;KAC5B,GAAG,SAAS,CAAC;CACf;AAED,wBAAgB,cAAc,CAAC,OAAO,EAAE,qBAAqB,GAAG,IAAI,CA8DnE"}
@@ -0,0 +1,52 @@
1
+ /**
2
+ * @file packages/chart-renderer-canvas/src/renderers/step-line-renderer.ts
3
+ * Step line (staircase) series renderer.
4
+ */
5
+ export function renderStepLine(options) {
6
+ const { ctx, data, xScale, yScale, color = '#3b82f6', strokeWidth = 2, areaFill, } = options;
7
+ if (data.length < 2)
8
+ return;
9
+ const validPoints = [];
10
+ for (let i = 0; i < data.length; i++) {
11
+ const v = data[i];
12
+ if (v !== null && v !== undefined && Number.isFinite(v)) {
13
+ validPoints.push({
14
+ x: xScale.scale(i),
15
+ y: yScale.scale(v),
16
+ });
17
+ }
18
+ }
19
+ if (validPoints.length < 2)
20
+ return;
21
+ ctx.save();
22
+ // Area Fill if requested
23
+ if (areaFill) {
24
+ ctx.fillStyle = areaFill.fillColor;
25
+ ctx.beginPath();
26
+ ctx.moveTo(validPoints[0].x, areaFill.baselineY);
27
+ ctx.lineTo(validPoints[0].x, validPoints[0].y);
28
+ for (let i = 0; i < validPoints.length - 1; i++) {
29
+ const p1 = validPoints[i];
30
+ const p2 = validPoints[i + 1];
31
+ ctx.lineTo(p2.x, p1.y);
32
+ ctx.lineTo(p2.x, p2.y);
33
+ }
34
+ ctx.lineTo(validPoints[validPoints.length - 1].x, areaFill.baselineY);
35
+ ctx.closePath();
36
+ ctx.fill();
37
+ }
38
+ // Step Stroke
39
+ ctx.strokeStyle = color;
40
+ ctx.lineWidth = strokeWidth;
41
+ ctx.beginPath();
42
+ ctx.moveTo(validPoints[0].x, validPoints[0].y);
43
+ for (let i = 0; i < validPoints.length - 1; i++) {
44
+ const p1 = validPoints[i];
45
+ const p2 = validPoints[i + 1];
46
+ // Horizontal step to p2.x, then vertical to p2.y
47
+ ctx.lineTo(p2.x, p1.y);
48
+ ctx.lineTo(p2.x, p2.y);
49
+ }
50
+ ctx.stroke();
51
+ ctx.restore();
52
+ }
@@ -0,0 +1,18 @@
1
+ /**
2
+ * @file packages/chart-renderer-canvas/src/renderers/supertrend-renderer.ts
3
+ * Canvas 2D renderer for the Supertrend trailing stop indicator.
4
+ * Draws dynamic green/red trend line with buy/sell reversal markers.
5
+ */
6
+ import type { Scale, SupertrendResult, IndexTimeScale } from '@tranding-custom-chart/core';
7
+ export interface SupertrendRenderOptions {
8
+ readonly ctx: CanvasRenderingContext2D;
9
+ readonly supertrend: SupertrendResult;
10
+ readonly xScale: IndexTimeScale | Scale<number>;
11
+ readonly yScale: Scale<number>;
12
+ readonly upColor?: string | undefined;
13
+ readonly downColor?: string | undefined;
14
+ readonly strokeWidth?: number | undefined;
15
+ readonly showReversalMarkers?: boolean | undefined;
16
+ }
17
+ export declare function renderSupertrend(options: SupertrendRenderOptions): void;
18
+ //# sourceMappingURL=supertrend-renderer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"supertrend-renderer.d.ts","sourceRoot":"","sources":["../../src/renderers/supertrend-renderer.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,KAAK,EAAE,gBAAgB,EAAE,cAAc,EAAE,MAAM,6BAA6B,CAAC;AAE3F,MAAM,WAAW,uBAAuB;IACtC,QAAQ,CAAC,GAAG,EAAE,wBAAwB,CAAC;IACvC,QAAQ,CAAC,UAAU,EAAE,gBAAgB,CAAC;IACtC,QAAQ,CAAC,MAAM,EAAE,cAAc,GAAG,KAAK,CAAC,MAAM,CAAC,CAAC;IAChD,QAAQ,CAAC,MAAM,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC;IAC/B,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACtC,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACxC,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC1C,QAAQ,CAAC,mBAAmB,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;CACpD;AAED,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,uBAAuB,GAAG,IAAI,CA0FvE"}
@@ -0,0 +1,80 @@
1
+ /**
2
+ * @file packages/chart-renderer-canvas/src/renderers/supertrend-renderer.ts
3
+ * Canvas 2D renderer for the Supertrend trailing stop indicator.
4
+ * Draws dynamic green/red trend line with buy/sell reversal markers.
5
+ */
6
+ export function renderSupertrend(options) {
7
+ const { ctx, supertrend, xScale, yScale, upColor = '#16a34a', // Bullish green
8
+ downColor = '#dc2626', // Bearish red
9
+ strokeWidth = 2, showReversalMarkers = true, } = options;
10
+ const points = supertrend.points;
11
+ if (!points || points.length === 0)
12
+ return;
13
+ ctx.save();
14
+ ctx.lineWidth = strokeWidth;
15
+ ctx.lineCap = 'round';
16
+ ctx.lineJoin = 'round';
17
+ const getX = (idx) => {
18
+ return 'slotCenter' in xScale ? xScale.slotCenter(idx) : xScale.scale(idx);
19
+ };
20
+ const period = supertrend.period ?? 10;
21
+ const startIdx = Math.min(points.length, Math.max(0, period - 1));
22
+ if (startIdx >= points.length)
23
+ return;
24
+ // Group contiguous segments of the same direction starting after warmup
25
+ let currentDirection = points[startIdx].direction;
26
+ let segmentStartIndex = startIdx;
27
+ for (let i = startIdx; i <= points.length; i++) {
28
+ const isEnd = i === points.length;
29
+ const dir = !isEnd ? points[i].direction : currentDirection;
30
+ if (isEnd || dir !== currentDirection) {
31
+ // Draw segment from segmentStartIndex to i - 1
32
+ ctx.beginPath();
33
+ ctx.strokeStyle = currentDirection === 1 ? upColor : downColor;
34
+ for (let j = segmentStartIndex; j < i; j++) {
35
+ const pt = points[j];
36
+ const x = getX(j);
37
+ const y = yScale.scale(pt.supertrend);
38
+ if (j === segmentStartIndex) {
39
+ ctx.moveTo(x, y);
40
+ }
41
+ else {
42
+ ctx.lineTo(x, y);
43
+ }
44
+ }
45
+ ctx.stroke();
46
+ if (!isEnd) {
47
+ currentDirection = dir;
48
+ segmentStartIndex = i;
49
+ }
50
+ }
51
+ }
52
+ // Draw Reversal Markers (Buy = Green Up Arrow / Pill, Sell = Red Down Arrow / Pill)
53
+ if (showReversalMarkers) {
54
+ for (let i = startIdx + 1; i < points.length; i++) {
55
+ const pt = points[i];
56
+ if (pt.isReversal) {
57
+ const x = getX(i);
58
+ const y = yScale.scale(pt.supertrend);
59
+ const isBuy = pt.direction === 1;
60
+ ctx.fillStyle = isBuy ? upColor : downColor;
61
+ ctx.beginPath();
62
+ if (isBuy) {
63
+ // Upward pointing triangle below price
64
+ ctx.moveTo(x, y + 4);
65
+ ctx.lineTo(x - 5, y + 14);
66
+ ctx.lineTo(x + 5, y + 14);
67
+ }
68
+ else {
69
+ // Downward pointing triangle above price
70
+ ctx.moveTo(x, y - 4);
71
+ ctx.lineTo(x - 5, y - 14);
72
+ ctx.lineTo(x + 5, y - 14);
73
+ }
74
+ ctx.closePath();
75
+ ctx.fill();
76
+ }
77
+ }
78
+ }
79
+ ctx.restore();
80
+ }
@@ -0,0 +1,25 @@
1
+ /**
2
+ * @file packages/chart-renderer-canvas/src/renderers/volume-profile-renderer.ts
3
+ * Canvas 2D renderer for Visible Range Volume Profile (VRVP) with POC line & Value Area.
4
+ */
5
+ import type { VolumeProfileResult, Scale } from '@tranding-custom-chart/core';
6
+ export interface VolumeProfileRenderOptions {
7
+ readonly ctx: CanvasRenderingContext2D;
8
+ readonly profile: VolumeProfileResult;
9
+ readonly yScale: Scale<number>;
10
+ readonly chartWidth: number;
11
+ readonly chartHeight: number;
12
+ readonly paddingRight: number;
13
+ readonly paddingLeft: number;
14
+ readonly maxBarWidth?: number | undefined;
15
+ readonly alignment?: 'right' | 'left' | undefined;
16
+ readonly buyColor?: string | undefined;
17
+ readonly sellColor?: string | undefined;
18
+ readonly valueAreaBuyColor?: string | undefined;
19
+ readonly valueAreaSellColor?: string | undefined;
20
+ readonly pocColor?: string | undefined;
21
+ readonly showPOCLine?: boolean | undefined;
22
+ readonly showLabels?: boolean | undefined;
23
+ }
24
+ export declare function renderVolumeProfile(options: VolumeProfileRenderOptions): void;
25
+ //# sourceMappingURL=volume-profile-renderer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"volume-profile-renderer.d.ts","sourceRoot":"","sources":["../../src/renderers/volume-profile-renderer.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,mBAAmB,EAAE,KAAK,EAAE,MAAM,6BAA6B,CAAC;AAG9E,MAAM,WAAW,0BAA0B;IACzC,QAAQ,CAAC,GAAG,EAAE,wBAAwB,CAAC;IACvC,QAAQ,CAAC,OAAO,EAAE,mBAAmB,CAAC;IACtC,QAAQ,CAAC,MAAM,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC;IAC/B,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC1C,QAAQ,CAAC,SAAS,CAAC,EAAE,OAAO,GAAG,MAAM,GAAG,SAAS,CAAC;IAClD,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACvC,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACxC,QAAQ,CAAC,iBAAiB,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAChD,QAAQ,CAAC,kBAAkB,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACjD,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACvC,QAAQ,CAAC,WAAW,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;IAC3C,QAAQ,CAAC,UAAU,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;CAC3C;AAED,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,0BAA0B,GAAG,IAAI,CA0G7E"}
@@ -0,0 +1,83 @@
1
+ /**
2
+ * @file packages/chart-renderer-canvas/src/renderers/volume-profile-renderer.ts
3
+ * Canvas 2D renderer for Visible Range Volume Profile (VRVP) with POC line & Value Area.
4
+ */
5
+ import { snapRect, snapLine } from '../dpi.js';
6
+ export function renderVolumeProfile(options) {
7
+ const { ctx, profile, yScale, chartWidth, paddingRight, paddingLeft, maxBarWidth = 140, alignment = 'right', buyColor = 'rgba(22, 121, 76, 0.35)', sellColor = 'rgba(180, 35, 24, 0.35)', valueAreaBuyColor = 'rgba(34, 197, 94, 0.6)', valueAreaSellColor = 'rgba(239, 68, 68, 0.6)', pocColor = '#f59e0b', showPOCLine = true, showLabels = true, } = options;
8
+ if (profile.bins.length === 0 || profile.pocVolume <= 0)
9
+ return;
10
+ const rightEdge = chartWidth - paddingRight;
11
+ const leftEdge = paddingLeft;
12
+ const maxVol = profile.pocVolume;
13
+ ctx.save();
14
+ // 1. Render Volume Bins
15
+ for (const bin of profile.bins) {
16
+ if (bin.totalVolume <= 0)
17
+ continue;
18
+ const yTop = yScale.scale(bin.priceHigh);
19
+ const yBottom = yScale.scale(bin.priceLow);
20
+ const barHeight = Math.max(2, Math.abs(yBottom - yTop) - 1);
21
+ const y = Math.min(yTop, yBottom);
22
+ const totalWidth = (bin.totalVolume / maxVol) * maxBarWidth;
23
+ const buyWidth = (bin.buyVolume / bin.totalVolume) * totalWidth;
24
+ const sellWidth = totalWidth - buyWidth;
25
+ const currentBuyColor = bin.isValueArea ? valueAreaBuyColor : buyColor;
26
+ const currentSellColor = bin.isValueArea ? valueAreaSellColor : sellColor;
27
+ if (alignment === 'right') {
28
+ const startX = rightEdge - totalWidth;
29
+ ctx.fillStyle = currentBuyColor;
30
+ ctx.fillRect(snapRect(startX), snapRect(y), snapRect(buyWidth), snapRect(barHeight));
31
+ ctx.fillStyle = currentSellColor;
32
+ ctx.fillRect(snapRect(startX + buyWidth), snapRect(y), snapRect(sellWidth), snapRect(barHeight));
33
+ }
34
+ else {
35
+ ctx.fillStyle = currentBuyColor;
36
+ ctx.fillRect(snapRect(leftEdge), snapRect(y), snapRect(buyWidth), snapRect(barHeight));
37
+ ctx.fillStyle = currentSellColor;
38
+ ctx.fillRect(snapRect(leftEdge + buyWidth), snapRect(y), snapRect(sellWidth), snapRect(barHeight));
39
+ }
40
+ }
41
+ // 2. Render Point of Control (POC) Line across chart
42
+ if (showPOCLine && profile.pocPrice > 0) {
43
+ const pocY = snapLine(yScale.scale(profile.pocPrice));
44
+ ctx.strokeStyle = pocColor;
45
+ ctx.lineWidth = 1.5;
46
+ ctx.setLineDash([4, 3]);
47
+ ctx.beginPath();
48
+ ctx.moveTo(leftEdge, pocY);
49
+ ctx.lineTo(rightEdge, pocY);
50
+ ctx.stroke();
51
+ ctx.setLineDash([]);
52
+ if (showLabels) {
53
+ ctx.fillStyle = pocColor;
54
+ ctx.fillRect(rightEdge - 85, pocY - 9, 83, 18);
55
+ ctx.fillStyle = '#000000';
56
+ ctx.font = '700 10px Inter, system-ui, sans-serif';
57
+ ctx.textAlign = 'center';
58
+ ctx.textBaseline = 'middle';
59
+ ctx.fillText(`POC ₹${profile.pocPrice.toFixed(1)}`, rightEdge - 43, pocY);
60
+ }
61
+ }
62
+ // 3. Render Value Area High (VAH) & Value Area Low (VAL)
63
+ if (showLabels && profile.vahPrice > 0 && profile.valPrice > 0) {
64
+ const vahY = snapLine(yScale.scale(profile.vahPrice));
65
+ const valY = snapLine(yScale.scale(profile.valPrice));
66
+ ctx.strokeStyle = 'rgba(255, 255, 255, 0.25)';
67
+ ctx.lineWidth = 1;
68
+ ctx.setLineDash([2, 4]);
69
+ ctx.beginPath();
70
+ ctx.moveTo(rightEdge - maxBarWidth - 10, vahY);
71
+ ctx.lineTo(rightEdge, vahY);
72
+ ctx.moveTo(rightEdge - maxBarWidth - 10, valY);
73
+ ctx.lineTo(rightEdge, valY);
74
+ ctx.stroke();
75
+ ctx.setLineDash([]);
76
+ ctx.fillStyle = 'rgba(255, 255, 255, 0.65)';
77
+ ctx.font = '500 9px Inter, system-ui, sans-serif';
78
+ ctx.textAlign = 'right';
79
+ ctx.fillText(`VAH ₹${profile.vahPrice.toFixed(1)}`, rightEdge - 6, vahY - 5);
80
+ ctx.fillText(`VAL ₹${profile.valPrice.toFixed(1)}`, rightEdge - 6, valY + 10);
81
+ }
82
+ ctx.restore();
83
+ }
@@ -0,0 +1,15 @@
1
+ /**
2
+ * @file packages/chart-renderer-canvas/src/renderers/watermark-renderer.ts
3
+ * Subtle background watermark displaying symbol identity and timeframe.
4
+ */
5
+ import type { Dimension, Padding } from '@tranding-custom-chart/core';
6
+ export interface WatermarkRenderOptions {
7
+ readonly ctx: CanvasRenderingContext2D;
8
+ readonly bounds: Dimension;
9
+ readonly padding: Padding;
10
+ readonly text: string;
11
+ readonly subText?: string | undefined;
12
+ readonly color?: string | undefined;
13
+ }
14
+ export declare function renderWatermark(options: WatermarkRenderOptions): void;
15
+ //# sourceMappingURL=watermark-renderer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"watermark-renderer.d.ts","sourceRoot":"","sources":["../../src/renderers/watermark-renderer.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,SAAS,EAAE,OAAO,EAAE,MAAM,6BAA6B,CAAC;AAEtE,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,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACtC,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CACrC;AAED,wBAAgB,eAAe,CAAC,OAAO,EAAE,sBAAsB,GAAG,IAAI,CAiCrE"}
@@ -0,0 +1,26 @@
1
+ /**
2
+ * @file packages/chart-renderer-canvas/src/renderers/watermark-renderer.ts
3
+ * Subtle background watermark displaying symbol identity and timeframe.
4
+ */
5
+ export function renderWatermark(options) {
6
+ const { ctx, bounds, padding, text, subText, color = 'rgba(255, 255, 255, 0.05)', } = options;
7
+ if (!text)
8
+ return;
9
+ const plotWidth = bounds.width - padding.left - padding.right;
10
+ const plotHeight = bounds.height - padding.top - padding.bottom;
11
+ const centerX = padding.left + plotWidth / 2;
12
+ const centerY = padding.top + plotHeight / 2;
13
+ ctx.save();
14
+ ctx.fillStyle = color;
15
+ ctx.textAlign = 'center';
16
+ ctx.textBaseline = 'middle';
17
+ // Responsive font size: roughly 10% of plot width, capped between 28px and 64px
18
+ const fontSize = Math.max(28, Math.min(64, Math.floor(plotWidth * 0.08)));
19
+ ctx.font = `bold ${fontSize}px sans-serif`;
20
+ ctx.fillText(text, centerX, subText ? centerY - fontSize * 0.35 : centerY);
21
+ if (subText) {
22
+ ctx.font = `500 ${Math.floor(fontSize * 0.45)}px sans-serif`;
23
+ ctx.fillText(subText, centerX, centerY + fontSize * 0.45);
24
+ }
25
+ ctx.restore();
26
+ }
@@ -0,0 +1,25 @@
1
+ /**
2
+ * @file packages/chart-renderer-canvas/src/scheduler.ts
3
+ * Coalesced requestAnimationFrame render scheduler.
4
+ * Batches high-frequency update requests into a single 60/120fps paint pass.
5
+ */
6
+ export declare class RenderScheduler {
7
+ private _frameId;
8
+ private _isDirty;
9
+ private readonly _renderCallback;
10
+ private _disposed;
11
+ constructor(renderCallback: () => void);
12
+ /**
13
+ * Marks the canvas as dirty and schedules a render pass on the next animation frame.
14
+ */
15
+ requestRender(): void;
16
+ /**
17
+ * Immediately runs a synchronous render pass if dirty, cancelling any pending rAF.
18
+ */
19
+ flushSync(): void;
20
+ isDirty(): boolean;
21
+ dispose(): void;
22
+ private _onFrame;
23
+ private _cancelPendingFrame;
24
+ }
25
+ //# sourceMappingURL=scheduler.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scheduler.d.ts","sourceRoot":"","sources":["../src/scheduler.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,qBAAa,eAAe;IAC1B,OAAO,CAAC,QAAQ,CAAuB;IACvC,OAAO,CAAC,QAAQ,CAAS;IACzB,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAa;IAC7C,OAAO,CAAC,SAAS,CAAS;gBAEd,cAAc,EAAE,MAAM,IAAI;IAItC;;OAEG;IACI,aAAa,IAAI,IAAI;IAc5B;;OAEG;IACI,SAAS,IAAI,IAAI;IASjB,OAAO,IAAI,OAAO;IAIlB,OAAO,IAAI,IAAI;IAMtB,OAAO,CAAC,QAAQ,CAad;IAEF,OAAO,CAAC,mBAAmB;CAU5B"}