@tradingaction/series 2.0.15

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 (119) hide show
  1. package/LICENSE +24 -0
  2. package/README.md +5 -0
  3. package/lib/AlternateDataSeries.d.ts +5 -0
  4. package/lib/AlternateDataSeries.js +16 -0
  5. package/lib/AlternateDataSeries.js.map +1 -0
  6. package/lib/AlternatingFillAreaSeries.d.ts +77 -0
  7. package/lib/AlternatingFillAreaSeries.js +69 -0
  8. package/lib/AlternatingFillAreaSeries.js.map +1 -0
  9. package/lib/AreaOnlySeries.d.ts +42 -0
  10. package/lib/AreaOnlySeries.js +53 -0
  11. package/lib/AreaOnlySeries.js.map +1 -0
  12. package/lib/AreaSeries.d.ts +46 -0
  13. package/lib/AreaSeries.js +21 -0
  14. package/lib/AreaSeries.js.map +1 -0
  15. package/lib/BarSeries.d.ts +36 -0
  16. package/lib/BarSeries.js +91 -0
  17. package/lib/BarSeries.js.map +1 -0
  18. package/lib/BollingerSeries.d.ts +33 -0
  19. package/lib/BollingerSeries.js +59 -0
  20. package/lib/BollingerSeries.js.map +1 -0
  21. package/lib/CandlestickSeries.d.ts +65 -0
  22. package/lib/CandlestickSeries.js +115 -0
  23. package/lib/CandlestickSeries.js.map +1 -0
  24. package/lib/ElderRaySeries.d.ts +45 -0
  25. package/lib/ElderRaySeries.js +66 -0
  26. package/lib/ElderRaySeries.js.map +1 -0
  27. package/lib/GroupedBarSeries.d.ts +33 -0
  28. package/lib/GroupedBarSeries.js +22 -0
  29. package/lib/GroupedBarSeries.js.map +1 -0
  30. package/lib/KagiSeries.d.ts +45 -0
  31. package/lib/KagiSeries.js +108 -0
  32. package/lib/KagiSeries.js.map +1 -0
  33. package/lib/LineSeries.d.ts +84 -0
  34. package/lib/LineSeries.js +102 -0
  35. package/lib/LineSeries.js.map +1 -0
  36. package/lib/MACDSeries.d.ts +55 -0
  37. package/lib/MACDSeries.js +62 -0
  38. package/lib/MACDSeries.js.map +1 -0
  39. package/lib/OHLCSeries.d.ts +32 -0
  40. package/lib/OHLCSeries.js +67 -0
  41. package/lib/OHLCSeries.js.map +1 -0
  42. package/lib/OverlayBarSeries.d.ts +35 -0
  43. package/lib/OverlayBarSeries.js +71 -0
  44. package/lib/OverlayBarSeries.js.map +1 -0
  45. package/lib/PointAndFigureSeries.d.ts +33 -0
  46. package/lib/PointAndFigureSeries.js +92 -0
  47. package/lib/PointAndFigureSeries.js.map +1 -0
  48. package/lib/RSISeries.d.ts +68 -0
  49. package/lib/RSISeries.js +82 -0
  50. package/lib/RSISeries.js.map +1 -0
  51. package/lib/RenkoSeries.d.ts +42 -0
  52. package/lib/RenkoSeries.js +65 -0
  53. package/lib/RenkoSeries.js.map +1 -0
  54. package/lib/SARSeries.d.ts +34 -0
  55. package/lib/SARSeries.js +69 -0
  56. package/lib/SARSeries.js.map +1 -0
  57. package/lib/SVGComponent.d.ts +8 -0
  58. package/lib/SVGComponent.js +9 -0
  59. package/lib/SVGComponent.js.map +1 -0
  60. package/lib/ScatterSeries.d.ts +24 -0
  61. package/lib/ScatterSeries.js +60 -0
  62. package/lib/ScatterSeries.js.map +1 -0
  63. package/lib/StackedBarSeries.d.ts +44 -0
  64. package/lib/StackedBarSeries.js +157 -0
  65. package/lib/StackedBarSeries.js.map +1 -0
  66. package/lib/StochasticSeries.d.ts +39 -0
  67. package/lib/StochasticSeries.js +42 -0
  68. package/lib/StochasticSeries.js.map +1 -0
  69. package/lib/StraightLine.d.ts +38 -0
  70. package/lib/StraightLine.js +81 -0
  71. package/lib/StraightLine.js.map +1 -0
  72. package/lib/VolumeProfileSeries.d.ts +45 -0
  73. package/lib/VolumeProfileSeries.js +161 -0
  74. package/lib/VolumeProfileSeries.js.map +1 -0
  75. package/lib/index.d.ts +23 -0
  76. package/lib/index.js +24 -0
  77. package/lib/index.js.map +1 -0
  78. package/lib/markers/CircleMarker.d.ts +25 -0
  79. package/lib/markers/CircleMarker.js +35 -0
  80. package/lib/markers/CircleMarker.js.map +1 -0
  81. package/lib/markers/SquareMarker.d.ts +25 -0
  82. package/lib/markers/SquareMarker.js +37 -0
  83. package/lib/markers/SquareMarker.js.map +1 -0
  84. package/lib/markers/TriangleMarker.d.ts +27 -0
  85. package/lib/markers/TriangleMarker.js +89 -0
  86. package/lib/markers/TriangleMarker.js.map +1 -0
  87. package/lib/markers/index.d.ts +3 -0
  88. package/lib/markers/index.js +4 -0
  89. package/lib/markers/index.js.map +1 -0
  90. package/package.json +52 -0
  91. package/src/AlternateDataSeries.tsx +29 -0
  92. package/src/AlternatingFillAreaSeries.tsx +159 -0
  93. package/src/AreaOnlySeries.tsx +106 -0
  94. package/src/AreaSeries.tsx +95 -0
  95. package/src/BarSeries.tsx +151 -0
  96. package/src/BollingerSeries.tsx +90 -0
  97. package/src/CandlestickSeries.tsx +188 -0
  98. package/src/ElderRaySeries.tsx +99 -0
  99. package/src/GroupedBarSeries.tsx +48 -0
  100. package/src/KagiSeries.tsx +155 -0
  101. package/src/LineSeries.tsx +223 -0
  102. package/src/MACDSeries.tsx +110 -0
  103. package/src/OHLCSeries.tsx +116 -0
  104. package/src/OverlayBarSeries.tsx +115 -0
  105. package/src/PointAndFigureSeries.tsx +140 -0
  106. package/src/RSISeries.tsx +158 -0
  107. package/src/RenkoSeries.tsx +118 -0
  108. package/src/SARSeries.tsx +111 -0
  109. package/src/SVGComponent.tsx +13 -0
  110. package/src/ScatterSeries.tsx +105 -0
  111. package/src/StackedBarSeries.tsx +272 -0
  112. package/src/StochasticSeries.tsx +70 -0
  113. package/src/StraightLine.tsx +166 -0
  114. package/src/VolumeProfileSeries.tsx +247 -0
  115. package/src/index.ts +23 -0
  116. package/src/markers/CircleMarker.tsx +69 -0
  117. package/src/markers/SquareMarker.tsx +71 -0
  118. package/src/markers/TriangleMarker.tsx +131 -0
  119. package/src/markers/index.ts +3 -0
@@ -0,0 +1,105 @@
1
+ import { functor, getAxisCanvas, GenericChartComponent } from "@tradingaction/core";
2
+ import { group } from "d3-array";
3
+ import { ScaleContinuousNumeric, ScaleTime } from "d3-scale";
4
+ import * as React from "react";
5
+
6
+ export interface ScatterSeriesProps {
7
+ /**
8
+ * A Marker to draw.
9
+ */
10
+ readonly marker?: any;
11
+ /**
12
+ * Given the data point return a Marker.
13
+ */
14
+ readonly markerProvider?: (datum: any) => any;
15
+ /**
16
+ * Props to pass to the marker.
17
+ */
18
+ readonly markerProps?: object;
19
+ /**
20
+ * Accessor for y value.
21
+ */
22
+ readonly yAccessor: (data: any) => number | undefined;
23
+ }
24
+
25
+ export class ScatterSeries extends React.Component<ScatterSeriesProps> {
26
+ public render() {
27
+ return <GenericChartComponent canvasDraw={this.drawOnCanvas} canvasToDraw={getAxisCanvas} drawOn={["pan"]} />;
28
+ }
29
+
30
+ private readonly drawOnCanvas = (ctx: CanvasRenderingContext2D, moreProps: any) => {
31
+ const points = this.getMarkers(moreProps);
32
+
33
+ const { markerProps } = this.props;
34
+
35
+ const nest = group(
36
+ points,
37
+ (d) => d.fillStyle,
38
+ (d) => d.strokeStyle,
39
+ );
40
+
41
+ nest.forEach((fillValues, fillKey) => {
42
+ if (fillKey !== "none") {
43
+ ctx.fillStyle = fillKey;
44
+ }
45
+
46
+ fillValues.forEach((strokeValues) => {
47
+ strokeValues.forEach((point) => {
48
+ const { marker } = point;
49
+ marker.drawOnCanvas({ ...marker.defaultProps, ...markerProps, fillStyle: fillKey }, point, ctx);
50
+ });
51
+ });
52
+ });
53
+ };
54
+
55
+ private readonly getMarkers = (moreProps: {
56
+ xAccessor: (data: any) => number | Date;
57
+ xScale: ScaleContinuousNumeric<number, number> | ScaleTime<number, number>;
58
+ chartConfig: any;
59
+ plotData: any[];
60
+ }) => {
61
+ const { yAccessor, markerProvider, markerProps } = this.props;
62
+
63
+ const {
64
+ xAccessor,
65
+ xScale,
66
+ chartConfig: { yScale },
67
+ plotData,
68
+ } = moreProps;
69
+
70
+ let { marker: Marker } = this.props;
71
+ if (!(markerProvider || Marker)) {
72
+ throw new Error("required prop, either marker or markerProvider missing");
73
+ }
74
+
75
+ return plotData
76
+ .map((d: any) => {
77
+ const yValue = yAccessor(d);
78
+ if (yValue === undefined) {
79
+ return undefined;
80
+ }
81
+
82
+ const xValue = xAccessor(d);
83
+
84
+ if (markerProvider) {
85
+ Marker = markerProvider(d);
86
+ }
87
+
88
+ const mProps = { ...Marker.defaultProps, ...markerProps };
89
+
90
+ const fill = functor(mProps.fillStyle);
91
+ const stroke = functor(mProps.strokeStyle);
92
+
93
+ return {
94
+ x: xScale(xValue),
95
+ y: yScale(yValue),
96
+ fillStyle: fill(d),
97
+ strokeStyle: stroke(d),
98
+ datum: d,
99
+ marker: Marker,
100
+ };
101
+ })
102
+ .filter((marker) => marker !== undefined)
103
+ .map((marker) => marker!);
104
+ };
105
+ }
@@ -0,0 +1,272 @@
1
+ import { group, merge } from "d3-array";
2
+ import { ScaleContinuousNumeric } from "d3-scale";
3
+ import { stack as d3Stack } from "d3-shape";
4
+ import * as React from "react";
5
+ import { functor, head, identity, getAxisCanvas, GenericChartComponent, plotDataLengthBarWidth } from "@tradingaction/core";
6
+
7
+ export interface StackedBarSeriesProps {
8
+ readonly baseAt?:
9
+ | number
10
+ | ((
11
+ xScale: ScaleContinuousNumeric<number, number>,
12
+ yScale: ScaleContinuousNumeric<number, number>,
13
+ d: [number, number],
14
+ moreProps: any,
15
+ ) => number);
16
+ readonly clip?: boolean;
17
+ readonly direction?: "up" | "down";
18
+ readonly fillStyle?: string | ((data: any, y: number) => string);
19
+ readonly spaceBetweenBar?: number;
20
+ readonly stroke?: boolean;
21
+ readonly swapScales?: boolean;
22
+ readonly yAccessor: ((data: any) => number | undefined) | ((d: any) => number)[];
23
+ readonly width?: number | ((props: StackedBarSeriesProps, moreProps: any) => number);
24
+ readonly widthRatio?: number;
25
+ }
26
+
27
+ export class StackedBarSeries extends React.Component<StackedBarSeriesProps> {
28
+ public static defaultProps = {
29
+ baseAt: (xScale: ScaleContinuousNumeric<number, number>, yScale: ScaleContinuousNumeric<number, number>) =>
30
+ head(yScale.range()),
31
+ direction: "up",
32
+ stroke: false,
33
+ fillStyle: "rgba(70, 130, 180, 0.5)",
34
+ width: plotDataLengthBarWidth,
35
+ widthRatio: 0.8,
36
+ clip: true,
37
+ swapScales: false,
38
+ };
39
+
40
+ public render() {
41
+ const { clip } = this.props;
42
+
43
+ return (
44
+ <GenericChartComponent
45
+ clip={clip}
46
+ canvasDraw={this.drawOnCanvas}
47
+ canvasToDraw={getAxisCanvas}
48
+ drawOn={["pan"]}
49
+ />
50
+ );
51
+ }
52
+
53
+ private readonly drawOnCanvas = (ctx: CanvasRenderingContext2D, moreProps: any) => {
54
+ const { xAccessor } = moreProps;
55
+
56
+ drawOnCanvasHelper(ctx, this.props, moreProps, xAccessor, d3Stack);
57
+ };
58
+ }
59
+
60
+ export function identityStack() {
61
+ let keys: any[] = [];
62
+ function stack(data: any) {
63
+ const response = keys.map((key, i) => {
64
+ const arrays = data.map((d: any) => {
65
+ const array = [0, d[key]];
66
+
67
+ // @ts-ignore
68
+ array.data = d;
69
+ return array;
70
+ });
71
+ arrays.key = key;
72
+ arrays.index = i;
73
+ return arrays;
74
+ });
75
+ return response;
76
+ }
77
+ stack.keys = function (x: any) {
78
+ if (!arguments.length) {
79
+ return keys;
80
+ }
81
+ keys = x;
82
+ return stack;
83
+ };
84
+ return stack;
85
+ }
86
+
87
+ export function drawOnCanvasHelper(
88
+ ctx: CanvasRenderingContext2D,
89
+ props: any,
90
+ moreProps: any,
91
+ xAccessor: any,
92
+ stackFn: any,
93
+ defaultPostAction = identity,
94
+ postRotateAction = rotateXY,
95
+ ) {
96
+ const {
97
+ xScale,
98
+ chartConfig: { yScale },
99
+ plotData,
100
+ } = moreProps;
101
+
102
+ const bars = doStuff(props, xAccessor, plotData, xScale, yScale, stackFn, postRotateAction, defaultPostAction);
103
+
104
+ drawOnCanvas2(props, ctx, bars);
105
+ }
106
+
107
+ function convertToArray(item: any) {
108
+ return Array.isArray(item) ? item : [item];
109
+ }
110
+
111
+ const doStuff = (
112
+ props: StackedBarSeriesProps,
113
+ xAccessor: any,
114
+ plotData: any[],
115
+ xScale: any,
116
+ yScale: any,
117
+ stackFn: any,
118
+ postRotateAction: any,
119
+ defaultPostAction: any,
120
+ ) => {
121
+ const { yAccessor, swapScales } = props;
122
+
123
+ const modifiedYAccessor = swapScales ? convertToArray(xAccessor) : convertToArray(yAccessor);
124
+ const modifiedXAccessor = swapScales ? yAccessor : xAccessor;
125
+
126
+ const modifiedXScale = swapScales ? yScale : xScale;
127
+ const modifiedYScale = swapScales ? xScale : yScale;
128
+
129
+ const postProcessor = swapScales ? postRotateAction : defaultPostAction;
130
+
131
+ const bars = getBars(
132
+ props,
133
+ modifiedXAccessor,
134
+ modifiedYAccessor,
135
+ modifiedXScale,
136
+ modifiedYScale,
137
+ plotData,
138
+ stackFn,
139
+ postProcessor,
140
+ );
141
+
142
+ return bars;
143
+ };
144
+
145
+ export const rotateXY = (array: any[]) =>
146
+ array.map((each) => {
147
+ return {
148
+ ...each,
149
+ x: each.y,
150
+ y: each.x,
151
+ height: each.width,
152
+ width: each.height,
153
+ };
154
+ });
155
+
156
+ export const drawOnCanvas2 = (props: { stroke?: boolean }, ctx: CanvasRenderingContext2D, bars: any) => {
157
+ const { stroke } = props;
158
+
159
+ const nest = group(bars, (d: any) => d.fillStyle);
160
+
161
+ nest.forEach((values, key) => {
162
+ if (head(values).width > 1) {
163
+ if (key !== undefined) {
164
+ ctx.strokeStyle = key;
165
+ }
166
+ }
167
+ ctx.fillStyle = key;
168
+
169
+ values.forEach((d) => {
170
+ if (d.width <= 1) {
171
+ ctx.fillRect(d.x - 0.5, d.y, 1, d.height);
172
+ } else {
173
+ ctx.fillRect(d.x + 0.5, d.y + 0.5, d.width, d.height);
174
+ if (stroke) {
175
+ ctx.strokeRect(d.x, d.y, d.width, d.height);
176
+ }
177
+ }
178
+ });
179
+ });
180
+ };
181
+
182
+ export function getBars(
183
+ props: StackedBarSeriesProps,
184
+ xAccessor: any,
185
+ yAccessor: any,
186
+ xScale: any,
187
+ yScale: any,
188
+ plotData: any[],
189
+ stack = identityStack,
190
+ after = identity,
191
+ ) {
192
+ const { baseAt, fillStyle, stroke, spaceBetweenBar = 0 } = props;
193
+
194
+ const getFill = functor(fillStyle);
195
+ const getBase = functor(baseAt);
196
+
197
+ const widthFunctor = functor(props.width);
198
+ const width = widthFunctor(props, {
199
+ xScale,
200
+ xAccessor,
201
+ plotData,
202
+ });
203
+
204
+ const barWidth = Math.round(width);
205
+
206
+ const eachBarWidth = (barWidth - spaceBetweenBar * (yAccessor.length - 1)) / yAccessor.length;
207
+
208
+ const offset = barWidth === 1 ? 0 : 0.5 * width;
209
+
210
+ const ds = plotData.map((each) => {
211
+ const d = {
212
+ appearance: {},
213
+ x: xAccessor(each),
214
+ };
215
+ yAccessor.forEach((eachYAccessor: any, i: number) => {
216
+ const key = `y${i}`;
217
+ // @ts-ignore
218
+ d[key] = eachYAccessor(each);
219
+ const appearance = {
220
+ stroke: stroke ? getFill(each, i) : "none",
221
+ fillStyle: getFill(each, i),
222
+ };
223
+ // @ts-ignore
224
+ d.appearance[key] = appearance;
225
+ });
226
+ return d;
227
+ });
228
+
229
+ const keys = yAccessor.map((_: any, i: number) => `y${i}`);
230
+
231
+ // @ts-ignore
232
+ const data = stack().keys(keys)(ds);
233
+
234
+ const newData = data.map((each: any, i: number) => {
235
+ const key = each.key;
236
+ return each.map((d: any) => {
237
+ const array = [d[0], d[1]];
238
+
239
+ // @ts-ignore
240
+ array.data = {
241
+ x: d.data.x,
242
+ i,
243
+ appearance: d.data.appearance[key],
244
+ };
245
+ return array;
246
+ });
247
+ });
248
+
249
+ const bars = merge<any>(newData)
250
+ .map((d) => {
251
+ let y = yScale(d[1]);
252
+ let h = getBase(xScale, yScale, d.data) - yScale(d[1] - d[0]);
253
+ if (h < 0) {
254
+ y = y + h;
255
+ h = -h;
256
+ }
257
+
258
+ return {
259
+ ...d.data.appearance,
260
+ x: Math.round(xScale(d.data.x) - width / 2),
261
+ y,
262
+ groupOffset: Math.round(offset - (d.data.i > 0 ? (eachBarWidth + spaceBetweenBar) * d.data.i : 0)),
263
+ groupWidth: Math.round(eachBarWidth),
264
+ offset: Math.round(offset),
265
+ height: h,
266
+ width: barWidth,
267
+ };
268
+ })
269
+ .filter((bar) => !isNaN(bar.y));
270
+
271
+ return after(bars);
272
+ }
@@ -0,0 +1,70 @@
1
+ import * as React from "react";
2
+
3
+ import { LineSeries } from "./LineSeries";
4
+ import { StraightLine } from "./StraightLine";
5
+
6
+ export interface StochasticSeriesProps {
7
+ readonly className?: string;
8
+ readonly overBought?: number;
9
+ readonly overSold?: number;
10
+ readonly middle?: number;
11
+ readonly strokeStyle?: {
12
+ top: string;
13
+ middle: string;
14
+ bottom: string;
15
+ dLine: string;
16
+ kLine: string;
17
+ };
18
+ readonly yAccessor: (data: any) => { K: number; D: number };
19
+ }
20
+
21
+ /**
22
+ * The Stochastic Oscillator is a momentum indicator that shows the location of the close relative to the high-low range over a set number of periods.
23
+ */
24
+ export class StochasticSeries extends React.Component<StochasticSeriesProps> {
25
+ public static defaultProps = {
26
+ className: "react-financial-charts-stochastic-series",
27
+ strokeStyle: {
28
+ top: "rgba(150, 75, 0, 0.3)",
29
+ middle: "rgba(0, 0, 0, 0.3)",
30
+ bottom: "rgba(150, 75, 0, 0.3)",
31
+ dLine: "#EA2BFF",
32
+ kLine: "#74D400",
33
+ },
34
+ overSold: 80,
35
+ middle: 50,
36
+ overBought: 20,
37
+ };
38
+
39
+ public render() {
40
+ const {
41
+ className,
42
+ strokeStyle = StochasticSeries.defaultProps.strokeStyle,
43
+ overSold,
44
+ middle,
45
+ overBought,
46
+ } = this.props;
47
+
48
+ return (
49
+ <g className={className}>
50
+ <LineSeries yAccessor={this.yAccessorForD} strokeStyle={strokeStyle.dLine} />
51
+ <LineSeries yAccessor={this.yAccessorForK} strokeStyle={strokeStyle.kLine} />
52
+ <StraightLine strokeStyle={strokeStyle.top} yValue={overSold} />
53
+ <StraightLine strokeStyle={strokeStyle.middle} yValue={middle} />
54
+ <StraightLine strokeStyle={strokeStyle.bottom} yValue={overBought} />
55
+ </g>
56
+ );
57
+ }
58
+
59
+ private readonly yAccessorForK = (d: any) => {
60
+ const { yAccessor } = this.props;
61
+
62
+ return yAccessor(d) && yAccessor(d).K;
63
+ };
64
+
65
+ private readonly yAccessorForD = (d: any) => {
66
+ const { yAccessor } = this.props;
67
+
68
+ return yAccessor(d) && yAccessor(d).D;
69
+ };
70
+ }
@@ -0,0 +1,166 @@
1
+ import { ScaleContinuousNumeric, ScaleTime } from "d3-scale";
2
+ import * as React from "react";
3
+ import { getAxisCanvas, getStrokeDasharrayCanvas, GenericChartComponent, strokeDashTypes } from "@tradingaction/core";
4
+
5
+ export type TStraightLineXLabelPosition = "bottom" | "top";
6
+
7
+ export interface StraightLineProps {
8
+ readonly lineDash?: strokeDashTypes | number[];
9
+ readonly lineWidth?: number;
10
+ readonly strokeStyle?: string;
11
+ readonly type?: "vertical" | "horizontal";
12
+ readonly yValue?: number;
13
+ readonly xValue?: number;
14
+
15
+ readonly xLabel?: string;
16
+ readonly xLabelPosition: TStraightLineXLabelPosition;
17
+ readonly xLabelFont: string; //'12px Arial'
18
+ readonly xLabelFill: string; //Background color
19
+ readonly xLabelColor: string; //'xLabel text color'
20
+ readonly xLabelPadding: number;
21
+
22
+ readonly onDoubleClick?: (e: React.MouseEvent, moreProps: any) => void;
23
+ readonly onClickOutside?: (e: React.MouseEvent, moreProps: any) => void;
24
+ readonly onContextMenuWhenHover?: (e: React.MouseEvent, moreProps: any) => void;
25
+ }
26
+
27
+ export class StraightLine extends React.Component<StraightLineProps> {
28
+ public static defaultProps = {
29
+ lineWidth: 1,
30
+ lineDash: "Solid",
31
+ strokeStyle: "rgba(0, 0, 0, 0.5)",
32
+ type: "horizontal",
33
+
34
+ xLabel: undefined,
35
+ xLabelPosition: "bottom",
36
+ xLabelFont: "12px Arial",
37
+ xLabelFill: "rgba(0, 0, 0, 0.7)",
38
+ xLabelColor: "#fff",
39
+ xLabelPadding: 5,
40
+ };
41
+
42
+ public render() {
43
+ return (
44
+ <GenericChartComponent
45
+ onContextMenu={this.props.onContextMenuWhenHover}
46
+ onDoubleClick={this.props.onDoubleClick}
47
+ onClickOutside={this.props.onClickOutside}
48
+ canvasDraw={this.drawOnCanvas}
49
+ canvasToDraw={getAxisCanvas}
50
+ drawOn={["pan", "mousemove", "drag"]}
51
+ />
52
+ );
53
+ }
54
+
55
+ private readonly drawOnCanvas = (ctx: CanvasRenderingContext2D, moreProps: any) => {
56
+ const {
57
+ type,
58
+ strokeStyle,
59
+ lineWidth,
60
+ lineDash,
61
+ yValue,
62
+ xValue,
63
+
64
+ xLabel,
65
+ xLabelPosition,
66
+ xLabelFont,
67
+ xLabelFill,
68
+ xLabelColor,
69
+ xLabelPadding,
70
+ } = this.props;
71
+
72
+ const {
73
+ xScale,
74
+ chartConfig: { yScale, width, height },
75
+ } = moreProps;
76
+
77
+ ctx.beginPath();
78
+
79
+ if (strokeStyle !== undefined) {
80
+ ctx.strokeStyle = strokeStyle;
81
+ }
82
+ if (lineWidth !== undefined) {
83
+ ctx.lineWidth = lineWidth;
84
+ }
85
+ if (lineDash !== undefined) {
86
+ ctx.setLineDash(typeof lineDash === "string" ? getStrokeDasharrayCanvas(lineDash) : lineDash);
87
+ }
88
+
89
+ const { x1, y1, x2, y2 } = this.getLineCoordinates(type, xScale, yScale, xValue, yValue, width, height);
90
+
91
+ ctx.moveTo(x1, y1);
92
+ ctx.lineTo(x2, y2);
93
+ ctx.stroke();
94
+
95
+ // Draw xLabel with background for vertical line at the bottom of the chart
96
+ // const xLabel = "Hi aman", xLabelFont = '12px Arial'
97
+ if (type === "vertical" && xLabel) {
98
+ // Horizontal support is not provided, because <PriceCoordinate /> could be used for left, and right with <StraightLine type="vertical" />
99
+ ctx.textAlign = "center";
100
+ ctx.textBaseline = "bottom";
101
+ ctx.font = xLabelFont || "12px Arial";
102
+
103
+ const { rectX, rectY, rectW, rectH, textX, textY } = this.getTextCoordinates(
104
+ ctx,
105
+ xLabel,
106
+ x1,
107
+ height,
108
+ xLabelPosition,
109
+ xLabelPadding,
110
+ );
111
+
112
+ // Set fill style for background
113
+ ctx.fillStyle = xLabelFill; // Provided or Semi-transparent black background
114
+ ctx.fillRect(rectX, rectY, rectW, rectH);
115
+
116
+ // Set fill style for text
117
+ ctx.fillStyle = xLabelColor;
118
+ ctx.fillText(xLabel, textX, textY);
119
+ }
120
+ };
121
+
122
+ private readonly getLineCoordinates = (
123
+ type: "horizontal" | "vertical" | undefined,
124
+ xScale: ScaleContinuousNumeric<number, number> | ScaleTime<number, number>,
125
+ yScale: ScaleContinuousNumeric<number, number>,
126
+ xValue: number | undefined,
127
+ yValue: number | undefined,
128
+ width: number,
129
+ height: number,
130
+ ) => {
131
+ return type === "horizontal"
132
+ ? { x1: 0, y1: Math.round(yScale(yValue!)), x2: width, y2: Math.round(yScale(yValue!)) }
133
+ : { x1: Math.round(xScale(xValue!)), y1: 0, x2: Math.round(xScale(xValue!)), y2: height };
134
+ };
135
+
136
+ private readonly getTextCoordinates = (
137
+ ctx: CanvasRenderingContext2D,
138
+ xLabel: string,
139
+ xPosition: number,
140
+ chartHeight: number,
141
+ xLabelPosition: TStraightLineXLabelPosition,
142
+ xLabelPadding: number,
143
+ ) => {
144
+ // Measure text to determine background size
145
+ const textMetrics = ctx.measureText(xLabel);
146
+ const textWidth = textMetrics.width;
147
+ const textHeight = parseInt(ctx.font, 10); // Approximate height from font
148
+
149
+ const rectX = xPosition - textWidth / 2 - xLabelPadding;
150
+ const rectY = xLabelPosition == "bottom" ? chartHeight - textHeight - 2 * xLabelPadding : 0;
151
+ const rectW = textWidth + 2 * xLabelPadding;
152
+ const rectH = textHeight + 2 * xLabelPadding;
153
+
154
+ const textX = xPosition;
155
+ const textY = xLabelPosition == "bottom" ? chartHeight - xLabelPadding : textHeight + xLabelPadding + 1;
156
+
157
+ return {
158
+ rectX,
159
+ rectY,
160
+ rectW,
161
+ rectH,
162
+ textX,
163
+ textY,
164
+ };
165
+ };
166
+ }