@tradingaction/interactive 2.0.13

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 (135) hide show
  1. package/LICENSE +24 -0
  2. package/README.md +5 -0
  3. package/lib/Brush.d.ts +35 -0
  4. package/lib/Brush.js +103 -0
  5. package/lib/Brush.js.map +1 -0
  6. package/lib/ClickCallback.d.ts +18 -0
  7. package/lib/ClickCallback.js +12 -0
  8. package/lib/ClickCallback.js.map +1 -0
  9. package/lib/DrawingObjectSelector.d.ts +18 -0
  10. package/lib/DrawingObjectSelector.js +73 -0
  11. package/lib/DrawingObjectSelector.js.map +1 -0
  12. package/lib/EquidistantChannel.d.ts +74 -0
  13. package/lib/EquidistantChannel.js +149 -0
  14. package/lib/EquidistantChannel.js.map +1 -0
  15. package/lib/FibonacciRetracement.d.ts +89 -0
  16. package/lib/FibonacciRetracement.js +184 -0
  17. package/lib/FibonacciRetracement.js.map +1 -0
  18. package/lib/GannFan.d.ts +78 -0
  19. package/lib/GannFan.js +128 -0
  20. package/lib/GannFan.js.map +1 -0
  21. package/lib/InteractiveText.d.ts +65 -0
  22. package/lib/InteractiveText.js +83 -0
  23. package/lib/InteractiveText.js.map +1 -0
  24. package/lib/InteractiveYCoordinate.d.ts +122 -0
  25. package/lib/InteractiveYCoordinate.js +100 -0
  26. package/lib/InteractiveYCoordinate.js.map +1 -0
  27. package/lib/StandardDeviationChannel.d.ts +74 -0
  28. package/lib/StandardDeviationChannel.js +125 -0
  29. package/lib/StandardDeviationChannel.js.map +1 -0
  30. package/lib/TrendLine.d.ts +84 -0
  31. package/lib/TrendLine.js +128 -0
  32. package/lib/TrendLine.js.map +1 -0
  33. package/lib/ZoomButtons.d.ts +30 -0
  34. package/lib/ZoomButtons.js +78 -0
  35. package/lib/ZoomButtons.js.map +1 -0
  36. package/lib/components/ChannelWithArea.d.ts +30 -0
  37. package/lib/components/ChannelWithArea.js +126 -0
  38. package/lib/components/ChannelWithArea.js.map +1 -0
  39. package/lib/components/ClickableCircle.d.ts +26 -0
  40. package/lib/components/ClickableCircle.js +48 -0
  41. package/lib/components/ClickableCircle.js.map +1 -0
  42. package/lib/components/ClickableShape.d.ts +33 -0
  43. package/lib/components/ClickableShape.js +64 -0
  44. package/lib/components/ClickableShape.js.map +1 -0
  45. package/lib/components/GannFan.d.ts +32 -0
  46. package/lib/components/GannFan.js +134 -0
  47. package/lib/components/GannFan.js.map +1 -0
  48. package/lib/components/HoverTextNearMouse.d.ts +35 -0
  49. package/lib/components/HoverTextNearMouse.js +113 -0
  50. package/lib/components/HoverTextNearMouse.js.map +1 -0
  51. package/lib/components/InteractiveStraightLine.d.ts +61 -0
  52. package/lib/components/InteractiveStraightLine.js +220 -0
  53. package/lib/components/InteractiveStraightLine.js.map +1 -0
  54. package/lib/components/InteractiveText.d.ts +38 -0
  55. package/lib/components/InteractiveText.js +84 -0
  56. package/lib/components/InteractiveText.js.map +1 -0
  57. package/lib/components/InteractiveYCoordinate.d.ts +46 -0
  58. package/lib/components/InteractiveYCoordinate.js +109 -0
  59. package/lib/components/InteractiveYCoordinate.js.map +1 -0
  60. package/lib/components/LinearRegressionChannelWithArea.d.ts +31 -0
  61. package/lib/components/LinearRegressionChannelWithArea.js +104 -0
  62. package/lib/components/LinearRegressionChannelWithArea.js.map +1 -0
  63. package/lib/components/MouseLocationIndicator.d.ts +34 -0
  64. package/lib/components/MouseLocationIndicator.js +79 -0
  65. package/lib/components/MouseLocationIndicator.js.map +1 -0
  66. package/lib/components/Text.d.ts +17 -0
  67. package/lib/components/Text.js +26 -0
  68. package/lib/components/Text.js.map +1 -0
  69. package/lib/components/index.d.ts +11 -0
  70. package/lib/components/index.js +12 -0
  71. package/lib/components/index.js.map +1 -0
  72. package/lib/index.d.ts +12 -0
  73. package/lib/index.js +13 -0
  74. package/lib/index.js.map +1 -0
  75. package/lib/utils.d.ts +7 -0
  76. package/lib/utils.js +84 -0
  77. package/lib/utils.js.map +1 -0
  78. package/lib/wrapper/EachEquidistantChannel.d.ts +59 -0
  79. package/lib/wrapper/EachEquidistantChannel.js +172 -0
  80. package/lib/wrapper/EachEquidistantChannel.js.map +1 -0
  81. package/lib/wrapper/EachFibRetracement.d.ts +81 -0
  82. package/lib/wrapper/EachFibRetracement.js +202 -0
  83. package/lib/wrapper/EachFibRetracement.js.map +1 -0
  84. package/lib/wrapper/EachGannFan.d.ts +81 -0
  85. package/lib/wrapper/EachGannFan.js +161 -0
  86. package/lib/wrapper/EachGannFan.js.map +1 -0
  87. package/lib/wrapper/EachInteractiveYCoordinate.d.ts +50 -0
  88. package/lib/wrapper/EachInteractiveYCoordinate.js +80 -0
  89. package/lib/wrapper/EachInteractiveYCoordinate.js.map +1 -0
  90. package/lib/wrapper/EachLinearRegressionChannel.d.ts +75 -0
  91. package/lib/wrapper/EachLinearRegressionChannel.js +89 -0
  92. package/lib/wrapper/EachLinearRegressionChannel.js.map +1 -0
  93. package/lib/wrapper/EachText.d.ts +59 -0
  94. package/lib/wrapper/EachText.js +83 -0
  95. package/lib/wrapper/EachText.js.map +1 -0
  96. package/lib/wrapper/EachTrendLine.d.ts +85 -0
  97. package/lib/wrapper/EachTrendLine.js +165 -0
  98. package/lib/wrapper/EachTrendLine.js.map +1 -0
  99. package/lib/wrapper/index.d.ts +7 -0
  100. package/lib/wrapper/index.js +8 -0
  101. package/lib/wrapper/index.js.map +1 -0
  102. package/package.json +53 -0
  103. package/src/Brush.tsx +172 -0
  104. package/src/ClickCallback.tsx +37 -0
  105. package/src/DrawingObjectSelector.tsx +97 -0
  106. package/src/EquidistantChannel.tsx +268 -0
  107. package/src/FibonacciRetracement.tsx +328 -0
  108. package/src/GannFan.tsx +233 -0
  109. package/src/InteractiveText.tsx +182 -0
  110. package/src/InteractiveYCoordinate.tsx +199 -0
  111. package/src/StandardDeviationChannel.tsx +269 -0
  112. package/src/TrendLine.tsx +294 -0
  113. package/src/ZoomButtons.tsx +165 -0
  114. package/src/components/ChannelWithArea.tsx +199 -0
  115. package/src/components/ClickableCircle.tsx +91 -0
  116. package/src/components/ClickableShape.tsx +114 -0
  117. package/src/components/GannFan.tsx +189 -0
  118. package/src/components/HoverTextNearMouse.tsx +174 -0
  119. package/src/components/InteractiveStraightLine.tsx +335 -0
  120. package/src/components/InteractiveText.tsx +146 -0
  121. package/src/components/InteractiveYCoordinate.tsx +200 -0
  122. package/src/components/LinearRegressionChannelWithArea.tsx +169 -0
  123. package/src/components/MouseLocationIndicator.tsx +128 -0
  124. package/src/components/Text.tsx +47 -0
  125. package/src/components/index.ts +11 -0
  126. package/src/index.ts +12 -0
  127. package/src/utils.ts +101 -0
  128. package/src/wrapper/EachEquidistantChannel.tsx +302 -0
  129. package/src/wrapper/EachFibRetracement.tsx +359 -0
  130. package/src/wrapper/EachGannFan.tsx +289 -0
  131. package/src/wrapper/EachInteractiveYCoordinate.tsx +198 -0
  132. package/src/wrapper/EachLinearRegressionChannel.tsx +202 -0
  133. package/src/wrapper/EachText.tsx +190 -0
  134. package/src/wrapper/EachTrendLine.tsx +331 -0
  135. package/src/wrapper/index.ts +7 -0
@@ -0,0 +1,146 @@
1
+ import * as React from "react";
2
+ import { getMouseCanvas, GenericChartComponent } from "@tradingaction/core";
3
+
4
+ export interface InteractiveTextProps {
5
+ readonly bgFillStyle: string;
6
+ readonly bgStrokeWidth: number;
7
+ readonly bgStroke: string;
8
+ readonly defaultClassName?: string;
9
+ readonly fontFamily: string;
10
+ readonly fontSize: number;
11
+ readonly fontWeight: number | string;
12
+ readonly fontStyle: string;
13
+ readonly onDragStart?: (e: React.MouseEvent, moreProps: any) => void;
14
+ readonly onDrag?: (e: React.MouseEvent, moreProps: any) => void;
15
+ readonly onDragComplete?: (e: React.MouseEvent, moreProps: any) => void;
16
+ readonly onHover?: (e: React.MouseEvent, moreProps: any) => void;
17
+ readonly onUnHover?: (e: React.MouseEvent, moreProps: any) => void;
18
+ readonly onDoubleClick?: (e: React.MouseEvent, moreProps: any) => void; //a1
19
+ readonly position?: any;
20
+ readonly interactiveCursorClass?: string;
21
+ readonly selected: boolean;
22
+ readonly text: string;
23
+ readonly textFill: string;
24
+ readonly tolerance: number;
25
+ }
26
+
27
+ export class InteractiveText extends React.Component<InteractiveTextProps> {
28
+ public static defaultProps = {
29
+ type: "SD", // standard dev
30
+ fontWeight: "normal", // standard dev
31
+ tolerance: 4,
32
+ selected: false,
33
+ };
34
+
35
+ private calculateTextWidth = true;
36
+ private textWidth?: number;
37
+
38
+ public componentDidUpdate(previousProps: InteractiveTextProps) {
39
+ this.calculateTextWidth =
40
+ previousProps.text !== this.props.text ||
41
+ previousProps.fontStyle !== this.props.fontStyle ||
42
+ previousProps.fontWeight !== this.props.fontWeight ||
43
+ previousProps.fontSize !== this.props.fontSize ||
44
+ previousProps.fontFamily !== this.props.fontFamily;
45
+ }
46
+
47
+ public render() {
48
+ const { selected, interactiveCursorClass } = this.props;
49
+ const { onHover, onUnHover } = this.props;
50
+ const { onDragStart, onDrag, onDragComplete, onDoubleClick } = this.props;
51
+
52
+ return (
53
+ <GenericChartComponent
54
+ isHover={this.isHover}
55
+ canvasToDraw={getMouseCanvas}
56
+ canvasDraw={this.drawOnCanvas}
57
+ interactiveCursorClass={interactiveCursorClass}
58
+ selected={selected}
59
+ onDragStart={onDragStart}
60
+ onDrag={onDrag}
61
+ onDragComplete={onDragComplete}
62
+ onDoubleClickWhenHover={onDoubleClick}
63
+ onHover={onHover}
64
+ onUnHover={onUnHover}
65
+ drawOn={["mousemove", "mouseleave", "pan", "drag"]}
66
+ />
67
+ );
68
+ }
69
+
70
+ private readonly isHover = (moreProps: any) => {
71
+ const { onHover } = this.props;
72
+
73
+ if (onHover !== undefined && this.textWidth !== undefined && !this.calculateTextWidth) {
74
+ const { rect } = this.helper(moreProps, this.textWidth);
75
+ const {
76
+ mouseXY: [x, y],
77
+ } = moreProps;
78
+
79
+ if (x >= rect.x && y >= rect.y && x <= rect.x + rect.width && y <= rect.y + rect.height) {
80
+ return true;
81
+ }
82
+ }
83
+ return false;
84
+ };
85
+
86
+ private readonly drawOnCanvas = (ctx: CanvasRenderingContext2D, moreProps: any) => {
87
+ const { bgFillStyle, bgStrokeWidth, bgStroke, textFill, fontFamily, fontSize, fontStyle, fontWeight, text } =
88
+ this.props;
89
+
90
+ if (this.calculateTextWidth) {
91
+ ctx.font = `${fontStyle} ${fontWeight} ${fontSize}px ${fontFamily}`;
92
+ const { width } = ctx.measureText(text);
93
+ this.textWidth = width;
94
+ this.calculateTextWidth = false;
95
+ }
96
+
97
+ const { selected } = this.props;
98
+
99
+ const { x, y, rect } = this.helper(moreProps, this.textWidth ?? 0);
100
+
101
+ ctx.fillStyle = bgFillStyle;
102
+
103
+ ctx.beginPath();
104
+ ctx.fillRect(rect.x, rect.y, rect.width, rect.height);
105
+
106
+ if (selected) {
107
+ ctx.strokeStyle = bgStroke;
108
+ ctx.lineWidth = bgStrokeWidth;
109
+ ctx.strokeRect(rect.x, rect.y, rect.width, rect.height);
110
+ }
111
+
112
+ ctx.fillStyle = textFill;
113
+ ctx.textBaseline = "middle";
114
+ ctx.textAlign = "center";
115
+ ctx.font = `${fontStyle} ${fontWeight} ${fontSize}px ${fontFamily}`;
116
+
117
+ ctx.beginPath();
118
+ ctx.fillText(text, x, y);
119
+ };
120
+
121
+ private readonly helper = (moreProps: any, textWidth: number) => {
122
+ const { position, fontSize } = this.props;
123
+
124
+ const {
125
+ xScale,
126
+ chartConfig: { yScale },
127
+ } = moreProps;
128
+
129
+ const [xValue, yValue] = position;
130
+ const x = xScale(xValue);
131
+ const y = yScale(yValue);
132
+
133
+ const rect = {
134
+ x: x - textWidth / 2 - fontSize,
135
+ y: y - fontSize,
136
+ width: textWidth + fontSize * 2,
137
+ height: fontSize * 2,
138
+ };
139
+
140
+ return {
141
+ x,
142
+ y,
143
+ rect,
144
+ };
145
+ };
146
+ }
@@ -0,0 +1,200 @@
1
+ import * as React from "react";
2
+ import { drawOnCanvas } from "@tradingaction/coordinates/lib/EdgeCoordinateV3";
3
+ import { getYCoordinate } from "@tradingaction/coordinates/lib/MouseCoordinateY";
4
+ import { getStrokeDasharrayCanvas, getMouseCanvas, GenericChartComponent, strokeDashTypes } from "@tradingaction/core";
5
+
6
+ export interface InteractiveYCoordinateProps {
7
+ readonly bgFillStyle: string;
8
+ readonly strokeStyle: string;
9
+ readonly strokeWidth: number;
10
+ readonly strokeDasharray: strokeDashTypes;
11
+ readonly textFill: string;
12
+ readonly fontFamily: string;
13
+ readonly fontSize: number;
14
+ readonly fontWeight: number | string;
15
+ readonly fontStyle: string;
16
+ readonly text: string;
17
+ readonly edge: object;
18
+ readonly textBox: {
19
+ readonly closeIcon: any;
20
+ readonly left: number;
21
+ readonly height: number;
22
+ readonly padding: any;
23
+ };
24
+ readonly yValue: number;
25
+ readonly onDragStart?: (e: React.MouseEvent, moreProps: any) => void;
26
+ readonly onDrag?: (e: React.MouseEvent, moreProps: any) => void;
27
+ readonly onDragComplete?: (e: React.MouseEvent, moreProps: any) => void;
28
+ readonly onHover?: (e: React.MouseEvent, moreProps: any) => void;
29
+ readonly onUnHover?: (e: React.MouseEvent, moreProps: any) => void;
30
+ readonly defaultClassName?: string;
31
+ readonly interactiveCursorClass?: string;
32
+ readonly tolerance: number;
33
+ readonly selected: boolean;
34
+ readonly hovering: boolean;
35
+ }
36
+
37
+ export class InteractiveYCoordinate extends React.Component<InteractiveYCoordinateProps> {
38
+ public static defaultProps = {
39
+ fontWeight: "normal", // standard dev
40
+ strokeWidth: 1,
41
+ tolerance: 4,
42
+ selected: false,
43
+ hovering: false,
44
+ };
45
+
46
+ private width = 0;
47
+
48
+ public render() {
49
+ const { interactiveCursorClass } = this.props;
50
+ const { onHover, onUnHover } = this.props;
51
+ const { onDragStart, onDrag, onDragComplete } = this.props;
52
+
53
+ return (
54
+ <GenericChartComponent
55
+ clip={false}
56
+ isHover={this.isHover}
57
+ canvasToDraw={getMouseCanvas}
58
+ canvasDraw={this.drawOnCanvas}
59
+ interactiveCursorClass={interactiveCursorClass}
60
+ enableDragOnHover
61
+ onDragStart={onDragStart}
62
+ onDrag={onDrag}
63
+ onDragComplete={onDragComplete}
64
+ onHover={onHover}
65
+ onUnHover={onUnHover}
66
+ drawOn={["mousemove", "mouseleave", "pan", "drag"]}
67
+ />
68
+ );
69
+ }
70
+
71
+ private readonly drawOnCanvas = (ctx: CanvasRenderingContext2D, moreProps: any) => {
72
+ const {
73
+ bgFillStyle,
74
+ textFill,
75
+ fontFamily,
76
+ fontSize,
77
+ fontStyle,
78
+ fontWeight,
79
+ strokeStyle,
80
+ strokeWidth,
81
+ strokeDasharray,
82
+ text,
83
+ textBox,
84
+ edge,
85
+ selected,
86
+ hovering,
87
+ } = this.props;
88
+
89
+ const values = this.helper(moreProps);
90
+ if (values == null) {
91
+ return;
92
+ }
93
+
94
+ const { x1, x2, y, rect } = values;
95
+
96
+ ctx.strokeStyle = strokeStyle;
97
+
98
+ ctx.beginPath();
99
+ if (selected || hovering) {
100
+ ctx.lineWidth = strokeWidth + 1;
101
+ } else {
102
+ ctx.lineWidth = strokeWidth;
103
+ }
104
+ ctx.textBaseline = "middle";
105
+ ctx.textAlign = "start";
106
+ ctx.font = `${fontStyle} ${fontWeight} ${fontSize}px ${fontFamily}`;
107
+
108
+ this.width =
109
+ textBox.padding.left +
110
+ ctx.measureText(text).width +
111
+ textBox.padding.right +
112
+ textBox.closeIcon.padding.left +
113
+ textBox.closeIcon.width +
114
+ textBox.closeIcon.padding.right;
115
+
116
+ ctx.setLineDash(getStrokeDasharrayCanvas(strokeDasharray));
117
+ ctx.moveTo(x1, y);
118
+ ctx.lineTo(rect.x, y);
119
+
120
+ ctx.moveTo(rect.x + this.width, y);
121
+ ctx.lineTo(x2, y);
122
+ ctx.stroke();
123
+
124
+ ctx.setLineDash([]);
125
+
126
+ ctx.fillStyle = bgFillStyle;
127
+
128
+ ctx.fillRect(rect.x, rect.y, this.width, rect.height);
129
+ ctx.strokeRect(rect.x, rect.y, this.width, rect.height);
130
+
131
+ ctx.fillStyle = textFill;
132
+
133
+ ctx.beginPath();
134
+ ctx.fillText(text, rect.x + 10, y);
135
+ const newEdge = {
136
+ ...edge,
137
+ textFill,
138
+ fontFamily,
139
+ fontSize,
140
+ };
141
+
142
+ // @ts-ignore
143
+ const yValue = edge.displayFormat(this.props.yValue);
144
+ const yCoord = getYCoordinate(y, yValue, newEdge, moreProps);
145
+ drawOnCanvas(ctx, yCoord);
146
+ };
147
+
148
+ private readonly isHover = (moreProps: any) => {
149
+ const { onHover } = this.props;
150
+
151
+ if (onHover !== undefined) {
152
+ const values = this.helper(moreProps);
153
+ if (values == null) {
154
+ return false;
155
+ }
156
+
157
+ const { x1, x2, y, rect } = values;
158
+ const {
159
+ mouseXY: [mouseX, mouseY],
160
+ } = moreProps;
161
+
162
+ if (
163
+ mouseX >= rect.x &&
164
+ mouseX <= rect.x + this.width &&
165
+ mouseY >= rect.y &&
166
+ mouseY <= rect.y + rect.height
167
+ ) {
168
+ return true;
169
+ }
170
+ if (x1 <= mouseX && x2 >= mouseX && Math.abs(mouseY - y) < 4) {
171
+ return true;
172
+ }
173
+ }
174
+ return false;
175
+ };
176
+
177
+ private readonly helper = (moreProps: any) => {
178
+ const { yValue, textBox } = this.props;
179
+
180
+ const {
181
+ chartConfig: { width, yScale, height },
182
+ } = moreProps;
183
+
184
+ const y = Math.round(yScale(yValue));
185
+
186
+ if (y >= 0 && y <= height) {
187
+ const rect = {
188
+ x: textBox.left,
189
+ y: y - textBox.height / 2,
190
+ height: textBox.height,
191
+ };
192
+ return {
193
+ x1: 0,
194
+ x2: width,
195
+ y,
196
+ rect,
197
+ };
198
+ }
199
+ };
200
+ }
@@ -0,0 +1,169 @@
1
+ import { deviation, sum, zip } from "d3-array";
2
+ import * as React from "react";
3
+ import { getClosestItemIndexes, getMouseCanvas, GenericChartComponent } from "@tradingaction/core";
4
+ import { isHovering2 } from "./InteractiveStraightLine";
5
+
6
+ export interface LinearRegressionChannelWithAreaProps {
7
+ readonly x1Value: any;
8
+ readonly x2Value: any;
9
+ readonly type:
10
+ | "SD" // standard deviation channel
11
+ | "Raff"; // Raff Regression Channel
12
+ readonly interactiveCursorClass?: string;
13
+ readonly strokeStyle: string;
14
+ readonly strokeWidth: number;
15
+ readonly fillStyle: string;
16
+ readonly onDragStart?: (e: React.MouseEvent, moreProps: any) => void;
17
+ readonly onDrag?: (e: React.MouseEvent, moreProps: any) => void;
18
+ readonly onDragComplete?: (e: React.MouseEvent, moreProps: any) => void;
19
+ readonly onHover?: (e: React.MouseEvent, moreProps: any) => void;
20
+ readonly onUnHover?: (e: React.MouseEvent, moreProps: any) => void;
21
+ readonly defaultClassName?: string;
22
+ readonly tolerance: number;
23
+ readonly selected: boolean;
24
+ }
25
+
26
+ export class LinearRegressionChannelWithArea extends React.Component<LinearRegressionChannelWithAreaProps> {
27
+ public static defaultProps = {
28
+ type: "SD", // standard dev
29
+ strokeWidth: 1,
30
+ tolerance: 4,
31
+ selected: false,
32
+ };
33
+
34
+ public render() {
35
+ const { selected, interactiveCursorClass } = this.props;
36
+ const { onDragStart, onDrag, onDragComplete, onHover, onUnHover } = this.props;
37
+
38
+ return (
39
+ <GenericChartComponent
40
+ isHover={this.isHover}
41
+ canvasToDraw={getMouseCanvas}
42
+ canvasDraw={this.drawOnCanvas}
43
+ interactiveCursorClass={interactiveCursorClass}
44
+ selected={selected}
45
+ onDragStart={onDragStart}
46
+ onDrag={onDrag}
47
+ onDragComplete={onDragComplete}
48
+ onHover={onHover}
49
+ onUnHover={onUnHover}
50
+ drawOn={["mousemove", "mouseleave", "pan", "drag"]}
51
+ />
52
+ );
53
+ }
54
+
55
+ private readonly drawOnCanvas = (ctx: CanvasRenderingContext2D, moreProps: any) => {
56
+ const { strokeStyle, strokeWidth, fillStyle } = this.props;
57
+ const { x1, y1, x2, y2, dy } = helper(this.props, moreProps);
58
+
59
+ ctx.lineWidth = strokeWidth;
60
+ ctx.strokeStyle = strokeStyle;
61
+ ctx.fillStyle = fillStyle;
62
+
63
+ ctx.beginPath();
64
+ ctx.moveTo(x1, y1 - dy);
65
+ ctx.lineTo(x2, y2 - dy);
66
+ ctx.stroke();
67
+
68
+ ctx.beginPath();
69
+ ctx.moveTo(x2, y2 + dy);
70
+ ctx.lineTo(x1, y1 + dy);
71
+ ctx.stroke();
72
+
73
+ ctx.beginPath();
74
+ ctx.moveTo(x1, y1 - dy);
75
+ ctx.lineTo(x2, y2 - dy);
76
+ ctx.lineTo(x2, y2 + dy);
77
+ ctx.lineTo(x1, y1 + dy);
78
+ ctx.closePath();
79
+ ctx.fill();
80
+
81
+ ctx.beginPath();
82
+ ctx.moveTo(x2, y2);
83
+ ctx.lineTo(x1, y1);
84
+ ctx.stroke();
85
+ };
86
+
87
+ private readonly isHover = (moreProps: any) => {
88
+ const { tolerance, onHover } = this.props;
89
+
90
+ if (onHover !== undefined) {
91
+ const { mouseXY } = moreProps;
92
+
93
+ const { x1, y1, x2, y2, dy } = helper(this.props, moreProps);
94
+ const yDiffs = [-dy, 0, dy];
95
+
96
+ const hovering = yDiffs.reduce(
97
+ (result, diff) => result || isHovering2([x1, y1 + diff], [x2, y2 + diff], mouseXY, tolerance),
98
+ false,
99
+ );
100
+ return hovering;
101
+ }
102
+ return false;
103
+ };
104
+ }
105
+
106
+ export function edge1Provider(props: any) {
107
+ return function (moreProps: any) {
108
+ const { x1, y1 } = helper(props, moreProps);
109
+ return [x1, y1];
110
+ };
111
+ }
112
+
113
+ export function edge2Provider(props: any) {
114
+ return function (moreProps: any) {
115
+ const { x2, y2 } = helper(props, moreProps);
116
+ return [x2, y2];
117
+ };
118
+ }
119
+
120
+ function helper(props: any, moreProps: any) {
121
+ const { x1Value, x2Value, type } = props;
122
+
123
+ const {
124
+ xScale,
125
+ chartConfig: { yScale },
126
+ fullData,
127
+ } = moreProps;
128
+ const { xAccessor } = moreProps;
129
+
130
+ const { left } = getClosestItemIndexes(fullData, x1Value, xAccessor);
131
+ const { right } = getClosestItemIndexes(fullData, x2Value, xAccessor);
132
+
133
+ const startIndex = Math.min(left, right);
134
+ const endIndex = Math.max(left, right) + 1;
135
+
136
+ const array = fullData.slice(startIndex, endIndex);
137
+
138
+ const xs = array.map((d: any) => xAccessor(d).valueOf());
139
+ const ys = array.map((d: any) => d.close);
140
+ const n = array.length;
141
+
142
+ const xys = zip<number>(xs, ys).map((d) => {
143
+ return d[0] * d[1];
144
+ });
145
+ const xSquareds = xs.map((x: any) => Math.pow(x, 2));
146
+
147
+ const b = (n * sum(xys) - sum(xs) * sum(ys)) / (n * sum(xSquareds) - Math.pow(sum(xs), 2));
148
+ const a = (sum(ys) - b * sum(xs)) / n;
149
+
150
+ const newy1 = a + b * x1Value;
151
+ const newy2 = a + b * x2Value;
152
+
153
+ const x1 = xScale(x1Value);
154
+ const y1 = yScale(newy1);
155
+ const x2 = xScale(x2Value);
156
+ const y2 = yScale(newy2);
157
+
158
+ const stdDev = type === "SD" ? deviation<any>(array, (d) => d.close) : 0;
159
+
160
+ const dy = yScale(newy1 - stdDev!) - y1;
161
+
162
+ return {
163
+ x1,
164
+ y1,
165
+ x2,
166
+ y2,
167
+ dy,
168
+ };
169
+ }
@@ -0,0 +1,128 @@
1
+ import {
2
+ functor,
3
+ getClosestValue,
4
+ getMouseCanvas,
5
+ GenericChartComponent,
6
+ isDefined,
7
+ noop,
8
+ shallowEqual,
9
+ } from "@tradingaction/core";
10
+ import * as React from "react";
11
+ import { getXValue } from "@tradingaction/core/lib/utils/ChartDataUtil";
12
+
13
+ export interface MouseLocationIndicatorProps {
14
+ readonly enabled: boolean;
15
+ readonly snap: boolean;
16
+ readonly shouldDisableSnap: (e: React.MouseEvent) => boolean;
17
+ readonly snapTo?: (datum: any) => number | number[];
18
+ readonly onMouseMove: (e: React.MouseEvent, xyValue: number[], moreProps: any) => void;
19
+ readonly onMouseDown: (e: React.MouseEvent, xyValue: number[], moreProps: any) => void;
20
+ readonly onClick: (e: React.MouseEvent, xyValue: number[], moreProps: any) => void;
21
+ readonly r: number;
22
+ readonly stroke: string;
23
+ readonly strokeWidth: number;
24
+ readonly opacity: number;
25
+ readonly disablePan: boolean;
26
+ }
27
+
28
+ export class MouseLocationIndicator extends React.Component<MouseLocationIndicatorProps> {
29
+ public static defaultProps = {
30
+ onMouseMove: noop,
31
+ onMouseDown: noop,
32
+ onClick: noop,
33
+ shouldDisableSnap: functor(false),
34
+ stroke: "#000000",
35
+ strokeWidth: 1,
36
+ opacity: 1,
37
+ disablePan: true,
38
+ };
39
+
40
+ private mutableState: any = {};
41
+
42
+ public render() {
43
+ const { enabled, disablePan } = this.props;
44
+
45
+ return (
46
+ <GenericChartComponent
47
+ onMouseDown={this.handleMouseDown}
48
+ onClick={this.handleClick}
49
+ onMouseMove={this.handleMousePosChange}
50
+ onPan={this.handleMousePosChange}
51
+ disablePan={enabled && disablePan}
52
+ canvasDraw={this.drawOnCanvas}
53
+ canvasToDraw={getMouseCanvas}
54
+ drawOn={["mousemove", "pan"]}
55
+ />
56
+ );
57
+ }
58
+
59
+ private readonly xy = (e: React.MouseEvent, moreProps: any) => {
60
+ const { xAccessor, plotData } = moreProps;
61
+ const {
62
+ mouseXY,
63
+ currentItem,
64
+ xScale,
65
+ chartConfig: { yScale },
66
+ } = moreProps;
67
+ const { enabled, snap, shouldDisableSnap, snapTo } = this.props;
68
+
69
+ if (enabled && isDefined(currentItem) && isDefined(e)) {
70
+ const xValue =
71
+ snap && !shouldDisableSnap(e)
72
+ ? xAccessor(currentItem)
73
+ : getXValue(xScale, xAccessor, mouseXY, plotData);
74
+ const yValue =
75
+ snap && snapTo !== undefined && !shouldDisableSnap(e)
76
+ ? getClosestValue(snapTo(currentItem), yScale.invert(mouseXY[1]))
77
+ : yScale.invert(mouseXY[1]);
78
+
79
+ const x = xScale(xValue);
80
+ const y = yScale(yValue);
81
+
82
+ return { xValue, yValue, x, y };
83
+ }
84
+ };
85
+
86
+ private readonly handleClick = (e: React.MouseEvent, moreProps: any) => {
87
+ const pos = this.xy(e, moreProps);
88
+ if (pos !== undefined && isDefined(pos)) {
89
+ const { xValue, yValue, x, y } = pos;
90
+ this.mutableState = { x, y };
91
+ this.props.onClick(e, [xValue, yValue], moreProps);
92
+ }
93
+ };
94
+
95
+ private readonly handleMouseDown = (e: React.MouseEvent, moreProps: any) => {
96
+ const pos = this.xy(e, moreProps);
97
+ if (pos !== undefined && isDefined(pos)) {
98
+ const { xValue, yValue, x, y } = pos;
99
+ this.mutableState = { x, y };
100
+ this.props.onMouseDown(e, [xValue, yValue], moreProps);
101
+ }
102
+ };
103
+
104
+ private readonly handleMousePosChange = (e: React.MouseEvent, moreProps: any) => {
105
+ if (!shallowEqual(moreProps.mousXY, moreProps.prevMouseXY)) {
106
+ const pos = this.xy(e, moreProps);
107
+ if (pos !== undefined && isDefined(pos)) {
108
+ const { xValue, yValue, x, y } = pos;
109
+ this.mutableState = { x, y };
110
+ this.props.onMouseMove(e, [xValue, yValue], moreProps);
111
+ }
112
+ }
113
+ };
114
+
115
+ private readonly drawOnCanvas = (ctx: CanvasRenderingContext2D, moreProps: any) => {
116
+ const { enabled, r, stroke, strokeWidth } = this.props;
117
+ const { x, y } = this.mutableState;
118
+ const { show } = moreProps;
119
+ if (enabled && show && isDefined(x)) {
120
+ ctx.lineWidth = strokeWidth;
121
+ ctx.strokeStyle = stroke;
122
+ ctx.moveTo(x, y);
123
+ ctx.beginPath();
124
+ ctx.arc(x, y, r, 0, 2 * Math.PI, false);
125
+ ctx.stroke();
126
+ }
127
+ };
128
+ }
@@ -0,0 +1,47 @@
1
+ import * as React from "react";
2
+ import { getMouseCanvas, GenericChartComponent } from "@tradingaction/core";
3
+
4
+ export interface TextProps {
5
+ readonly children: string;
6
+ readonly fontFamily: string;
7
+ readonly fontSize: number;
8
+ readonly fillStyle: string;
9
+ readonly selected?: boolean;
10
+ readonly xyProvider: (moreProps: any) => number[];
11
+ }
12
+
13
+ export class Text extends React.Component<TextProps> {
14
+ public static defaultProps = {
15
+ selected: false,
16
+ };
17
+
18
+ public render() {
19
+ const { selected } = this.props;
20
+
21
+ return (
22
+ <GenericChartComponent
23
+ isHover={this.isHover}
24
+ selected={selected}
25
+ canvasToDraw={getMouseCanvas}
26
+ canvasDraw={this.drawOnCanvas}
27
+ drawOn={["mousemove", "pan", "drag"]}
28
+ />
29
+ );
30
+ }
31
+
32
+ private readonly isHover = () => {
33
+ return false;
34
+ };
35
+
36
+ private readonly drawOnCanvas = (ctx: CanvasRenderingContext2D, moreProps: any) => {
37
+ const { xyProvider, fontFamily, fontSize, fillStyle, children } = this.props;
38
+
39
+ const [x, y] = xyProvider(moreProps);
40
+
41
+ ctx.font = `${fontSize}px ${fontFamily}`;
42
+ ctx.fillStyle = fillStyle;
43
+
44
+ ctx.beginPath();
45
+ ctx.fillText(children, x, y);
46
+ };
47
+ }
@@ -0,0 +1,11 @@
1
+ export * from "./ChannelWithArea";
2
+ export * from "./ClickableCircle";
3
+ export * from "./ClickableShape";
4
+ export * from "./GannFan";
5
+ export * from "./HoverTextNearMouse";
6
+ export * from "./InteractiveStraightLine";
7
+ export * from "./InteractiveText";
8
+ export * from "./InteractiveYCoordinate";
9
+ export * from "./LinearRegressionChannelWithArea";
10
+ export * from "./MouseLocationIndicator";
11
+ export * from "./Text";