@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,97 @@
1
+ import * as React from "react";
2
+ import { head, isDefined, mapObject, GenericComponent, getMouseCanvas } from "@tradingaction/core";
3
+ import { getMorePropsForChart, getSelected } from "./utils";
4
+
5
+ interface DrawingObjectSelectorProps {
6
+ readonly getInteractiveNodes: () => any[];
7
+ readonly onSelect?: (e: React.MouseEvent, interactives: any[], moreProps: any) => void;
8
+ readonly onDoubleClick?: (e: React.MouseEvent, item: any, moreProps: any) => void;
9
+ readonly drawingObjectMap: any;
10
+ readonly enabled: boolean;
11
+ }
12
+
13
+ export class DrawingObjectSelector extends React.Component<DrawingObjectSelectorProps> {
14
+ public static defaultProps = {
15
+ enabled: true,
16
+ };
17
+
18
+ public render() {
19
+ return (
20
+ <GenericComponent
21
+ canvasToDraw={getMouseCanvas}
22
+ onMouseDown={this.handleClick}
23
+ onDoubleClick={this.handleDoubleClick}
24
+ drawOn={["mousemove", "pan", "drag"]}
25
+ />
26
+ );
27
+ }
28
+
29
+ private readonly getInteraction = (moreProps: any) => {
30
+ const { getInteractiveNodes, drawingObjectMap } = this.props;
31
+ const interactiveNodes = getInteractiveNodes();
32
+ const interactives = mapObject(interactiveNodes, (each) => {
33
+ const key = drawingObjectMap[each.type];
34
+
35
+ const valueArray = isDefined(key) ? each.node.props[key] : undefined;
36
+
37
+ const valuePresent = isDefined(valueArray) && Array.isArray(valueArray) && valueArray.length > 0;
38
+ if (valuePresent) {
39
+ const morePropsForChart = getMorePropsForChart(moreProps, each.chartId);
40
+
41
+ const objects = each.node.getSelectionState(morePropsForChart);
42
+
43
+ return {
44
+ type: each.type,
45
+ chartId: each.chartId,
46
+ objects,
47
+ };
48
+ }
49
+ return {
50
+ type: each.type,
51
+ chartId: each.chartId,
52
+ objects: [],
53
+ };
54
+ });
55
+
56
+ return interactives;
57
+ };
58
+
59
+ private readonly handleClick = (e: React.MouseEvent, moreProps: any) => {
60
+ e.preventDefault();
61
+ const { onSelect } = this.props;
62
+ const { enabled } = this.props;
63
+ if (!enabled) {
64
+ return;
65
+ }
66
+
67
+ const interactives = this.getInteraction(moreProps);
68
+ if (onSelect !== undefined) {
69
+ onSelect(e, interactives, moreProps);
70
+ }
71
+ };
72
+
73
+ private readonly handleDoubleClick = (e: React.MouseEvent, moreProps: any) => {
74
+ e.preventDefault();
75
+ const { onDoubleClick } = this.props;
76
+ const { enabled } = this.props;
77
+ if (!enabled) {
78
+ return;
79
+ }
80
+
81
+ const interactives = this.getInteraction(moreProps);
82
+ const allSelected = getSelected(interactives);
83
+
84
+ if (allSelected.length > 0) {
85
+ const selected = head(allSelected);
86
+ const item = {
87
+ type: selected.type,
88
+ chartId: selected.chartId,
89
+ object: head(selected.objects),
90
+ };
91
+ const morePropsForChart = getMorePropsForChart(moreProps, selected.chartId);
92
+ if (onDoubleClick !== undefined) {
93
+ onDoubleClick(e, item, morePropsForChart);
94
+ }
95
+ }
96
+ };
97
+ }
@@ -0,0 +1,268 @@
1
+ import * as React from "react";
2
+ import { isDefined, isNotDefined, noop } from "@tradingaction/core";
3
+ import { HoverTextNearMouse, MouseLocationIndicator } from "./components";
4
+ import { getSlope, getYIntercept } from "./components/InteractiveStraightLine";
5
+ import { isHoverForInteractiveType, saveNodeType, terminate } from "./utils";
6
+ import { EachEquidistantChannel } from "./wrapper";
7
+
8
+ interface EquidistantChannelProps {
9
+ readonly enabled: boolean;
10
+ readonly onStart: () => void;
11
+ readonly onComplete: (e: React.MouseEvent, newChannels: any[], moreProps: any) => void;
12
+ readonly onSelect: (e: React.MouseEvent, interactives: any[], moreProps: any) => void;
13
+ readonly currentPositionStroke?: string;
14
+ readonly currentPositionStrokeWidth?: number;
15
+ readonly currentPositionOpacity?: number;
16
+ readonly currentPositionRadius?: number;
17
+ readonly hoverText: object;
18
+ readonly channels: any[];
19
+ readonly appearance: {
20
+ readonly stroke: string;
21
+ readonly strokeOpacity: number;
22
+ readonly strokeWidth: number;
23
+ readonly fill: string;
24
+ readonly fillOpacity: number;
25
+ readonly edgeStroke: string;
26
+ readonly edgeFill: string;
27
+ readonly edgeFill2: string;
28
+ readonly edgeStrokeWidth: number;
29
+ readonly r: number;
30
+ };
31
+ }
32
+
33
+ interface EquidistantChannelState {
34
+ current?: any;
35
+ override?: any;
36
+ }
37
+
38
+ export class EquidistantChannel extends React.Component<EquidistantChannelProps, EquidistantChannelState> {
39
+ public static defaultProps = {
40
+ onSelect: noop,
41
+ currentPositionStroke: "#000000",
42
+ currentPositionOpacity: 1,
43
+ currentPositionStrokeWidth: 3,
44
+ currentPositionRadius: 4,
45
+ hoverText: {
46
+ ...HoverTextNearMouse.defaultProps,
47
+ enable: true,
48
+ bgHeight: 18,
49
+ bgWidth: 120,
50
+ text: "Click to select object",
51
+ },
52
+ channels: [],
53
+ appearance: {
54
+ stroke: "#000000",
55
+ strokeOpacity: 1,
56
+ strokeWidth: 1,
57
+ fill: "#8AAFE2",
58
+ fillOpacity: 0.7,
59
+ edgeStroke: "#000000",
60
+ edgeFill: "#FFFFFF",
61
+ edgeFill2: "#250B98",
62
+ edgeStrokeWidth: 1,
63
+ r: 5,
64
+ },
65
+ };
66
+
67
+ // @ts-ignore
68
+ private terminate: () => void;
69
+ private saveNodeType: any;
70
+ // @ts-ignore
71
+ private getSelectionState: any;
72
+ private mouseMoved: any;
73
+
74
+ public constructor(props: EquidistantChannelProps) {
75
+ super(props);
76
+
77
+ this.terminate = terminate.bind(this);
78
+ this.saveNodeType = saveNodeType.bind(this);
79
+ this.getSelectionState = isHoverForInteractiveType("channels").bind(this);
80
+
81
+ this.state = {};
82
+ }
83
+
84
+ public render() {
85
+ const {
86
+ appearance,
87
+ channels,
88
+ currentPositionOpacity,
89
+ currentPositionRadius = EquidistantChannel.defaultProps.currentPositionRadius,
90
+ currentPositionStroke,
91
+ currentPositionStrokeWidth,
92
+ enabled,
93
+ hoverText,
94
+ } = this.props;
95
+
96
+ const { current, override } = this.state;
97
+
98
+ const overrideIndex = isDefined(override) ? override.index : null;
99
+
100
+ const tempChannel =
101
+ isDefined(current) && isDefined(current.endXY) ? (
102
+ <EachEquidistantChannel
103
+ interactive={false}
104
+ {...current}
105
+ appearance={appearance}
106
+ hoverText={hoverText}
107
+ />
108
+ ) : null;
109
+
110
+ return (
111
+ <g>
112
+ {channels.map((each, idx) => {
113
+ const eachAppearance = isDefined(each.appearance)
114
+ ? { ...appearance, ...each.appearance }
115
+ : appearance;
116
+
117
+ return (
118
+ <EachEquidistantChannel
119
+ key={idx}
120
+ ref={this.saveNodeType(idx)}
121
+ index={idx}
122
+ selected={each.selected}
123
+ hoverText={hoverText}
124
+ {...(idx === overrideIndex ? override : each)}
125
+ appearance={eachAppearance}
126
+ onDrag={this.handleDragChannel}
127
+ onDragComplete={this.handleDragChannelComplete}
128
+ />
129
+ );
130
+ })}
131
+ {tempChannel}
132
+ <MouseLocationIndicator
133
+ enabled={enabled}
134
+ snap={false}
135
+ r={currentPositionRadius}
136
+ stroke={currentPositionStroke}
137
+ opacity={currentPositionOpacity}
138
+ strokeWidth={currentPositionStrokeWidth}
139
+ onMouseDown={this.handleStart}
140
+ onClick={this.handleEnd}
141
+ onMouseMove={this.handleDrawChannel}
142
+ />
143
+ </g>
144
+ );
145
+ }
146
+
147
+ private readonly handleDragChannel = (_: React.MouseEvent, index: any, newXYValue: any) => {
148
+ this.setState({
149
+ override: {
150
+ index,
151
+ ...newXYValue,
152
+ },
153
+ });
154
+ };
155
+
156
+ private readonly handleDragChannelComplete = (e: React.MouseEvent, moreProps: any) => {
157
+ const { override } = this.state;
158
+ const { channels } = this.props;
159
+
160
+ if (isDefined(override)) {
161
+ const { index, ...rest } = override;
162
+ const newChannels = channels.map((each, idx) =>
163
+ idx === index ? { ...each, ...rest, selected: true } : each,
164
+ );
165
+
166
+ this.setState(
167
+ {
168
+ override: null,
169
+ },
170
+ () => {
171
+ const { onComplete } = this.props;
172
+ if (onComplete !== undefined) {
173
+ onComplete(e, newChannels, moreProps);
174
+ }
175
+ },
176
+ );
177
+ }
178
+ };
179
+
180
+ private readonly handleStart = (_: React.MouseEvent, xyValue: any) => {
181
+ const { current } = this.state;
182
+
183
+ if (isNotDefined(current) || isNotDefined(current.startXY)) {
184
+ this.mouseMoved = false;
185
+ this.setState(
186
+ {
187
+ current: {
188
+ startXY: xyValue,
189
+ endXY: null,
190
+ },
191
+ },
192
+ () => {
193
+ const { onStart } = this.props;
194
+ if (onStart !== undefined) {
195
+ onStart();
196
+ }
197
+ },
198
+ );
199
+ }
200
+ };
201
+
202
+ private readonly handleEnd = (e: React.MouseEvent, _: any, moreProps: any) => {
203
+ const { current } = this.state;
204
+ const { channels, appearance } = this.props;
205
+
206
+ if (this.mouseMoved && isDefined(current) && isDefined(current.startXY)) {
207
+ if (isNotDefined(current.dy)) {
208
+ this.setState({
209
+ current: {
210
+ ...current,
211
+ dy: 0,
212
+ },
213
+ });
214
+ } else {
215
+ const newChannels = [
216
+ ...channels.map((d) => ({ ...d, selected: false })),
217
+ {
218
+ ...current,
219
+ selected: true,
220
+ appearance,
221
+ },
222
+ ];
223
+
224
+ this.setState(
225
+ {
226
+ current: null,
227
+ },
228
+ () => {
229
+ const { onComplete } = this.props;
230
+ if (onComplete !== undefined) {
231
+ onComplete(e, newChannels, moreProps);
232
+ }
233
+ },
234
+ );
235
+ }
236
+ }
237
+ };
238
+
239
+ private readonly handleDrawChannel = (_: React.MouseEvent, xyValue: any) => {
240
+ const { current } = this.state;
241
+
242
+ if (isDefined(current) && isDefined(current.startXY)) {
243
+ this.mouseMoved = true;
244
+ if (isNotDefined(current.dy)) {
245
+ this.setState({
246
+ current: {
247
+ startXY: current.startXY,
248
+ endXY: xyValue,
249
+ },
250
+ });
251
+ } else {
252
+ const m = getSlope(current.startXY, current.endXY);
253
+ const b = getYIntercept(m, current.endXY);
254
+
255
+ // @ts-ignore
256
+ const y = m * xyValue[0] + b;
257
+ const dy = xyValue[1] - y;
258
+
259
+ this.setState({
260
+ current: {
261
+ ...current,
262
+ dy,
263
+ },
264
+ });
265
+ }
266
+ }
267
+ };
268
+ }
@@ -0,0 +1,328 @@
1
+ import * as React from "react";
2
+ import { isDefined, isNotDefined, noop } from "@tradingaction/core";
3
+ import { HoverTextNearMouse, MouseLocationIndicator } from "./components";
4
+ import { isHoverForInteractiveType, saveNodeType, terminate } from "./utils";
5
+ import { EachFibRetracement } from "./wrapper";
6
+
7
+ interface FibonacciRetracementProps {
8
+ readonly enabled: boolean;
9
+ readonly width?: number;
10
+ readonly onStart?: (moreProps: any) => void;
11
+ readonly onComplete?: (e: React.MouseEvent, newRetracements: any[], moreProps: any) => void;
12
+ readonly onSelect?: (e: React.MouseEvent, interactives: any[], moreProps: any) => void;
13
+ readonly onDoubleClick?: (e: React.MouseEvent, moreProps: any, idx: any) => void;
14
+ readonly onClickWhenHover?: (e: React.MouseEvent, moreProps: any, idx: any) => void;
15
+ readonly onClickOutside?: (e: React.MouseEvent, moreProps: any, idx: any) => void;
16
+ readonly onConextMenu?: (e: React.MouseEvent, moreProps: any, idx: any) => void;
17
+ readonly type:
18
+ | "EXTEND" // extends from -Infinity to +Infinity
19
+ | "RAY" // extends to +/-Infinity in one direction
20
+ | "BOUND"; // extends between the set bounds
21
+ readonly hoverText: object;
22
+ readonly currentPositionStroke?: string;
23
+ readonly currentPositionStrokeWidth?: number;
24
+ readonly currentPositionOpacity?: number;
25
+ readonly currentPositionRadius?: number;
26
+ readonly retracements: any[];
27
+ readonly appearance: {
28
+ readonly strokeStyle: string;
29
+ readonly strokeWidth: number;
30
+ readonly fontFamily: string;
31
+ readonly fontSize: number;
32
+ readonly fontFill: string;
33
+ readonly edgeStroke: string;
34
+ readonly edgeFill: string;
35
+ readonly nsEdgeFill: string;
36
+ readonly edgeStrokeWidth: number;
37
+ readonly r: number;
38
+ };
39
+ }
40
+
41
+ interface FibonacciRetracementState {
42
+ current?: any;
43
+ override?: any;
44
+ }
45
+
46
+ export class FibonacciRetracement extends React.Component<FibonacciRetracementProps, FibonacciRetracementState> {
47
+ public static defaultProps = {
48
+ enabled: true,
49
+ type: "RAY",
50
+ retracements: [],
51
+ onSelect: noop,
52
+ hoverText: {
53
+ ...HoverTextNearMouse.defaultProps,
54
+ enable: true,
55
+ bgHeight: "auto",
56
+ bgWidth: "auto",
57
+ text: "Click to select object",
58
+ selectedText: "",
59
+ },
60
+ currentPositionStroke: "#000000",
61
+ currentPositionOpacity: 1,
62
+ currentPositionStrokeWidth: 3,
63
+ currentPositionRadius: 4,
64
+ appearance: {
65
+ strokeStyle: "#000000",
66
+ strokeWidth: 1,
67
+ fontFamily: "-apple-system, system-ui, Roboto, 'Helvetica Neue', Ubuntu, sans-serif",
68
+ fontSize: 11,
69
+ fontFill: "#000000",
70
+ edgeStroke: "#000000",
71
+ edgeFill: "#FFFFFF",
72
+ nsEdgeFill: "#000000",
73
+ edgeStrokeWidth: 1,
74
+ r: 5,
75
+ },
76
+ };
77
+
78
+ // @ts-ignore
79
+ private getSelectionState: any;
80
+ private mouseMoved: any;
81
+ private saveNodeType: any;
82
+ // @ts-ignore
83
+ private terminate: any;
84
+
85
+ public constructor(props: FibonacciRetracementProps) {
86
+ super(props);
87
+
88
+ this.handleEdge1Drag = this.handleEdge1Drag.bind(this);
89
+ this.handleEdge2Drag = this.handleEdge2Drag.bind(this);
90
+
91
+ this.terminate = terminate.bind(this);
92
+ this.getSelectionState = isHoverForInteractiveType("retracements").bind(this);
93
+
94
+ this.saveNodeType = saveNodeType.bind(this);
95
+ this.state = {};
96
+ }
97
+
98
+ public render() {
99
+ const { current, override } = this.state;
100
+
101
+ const {
102
+ appearance,
103
+ currentPositionStroke,
104
+ currentPositionOpacity,
105
+ currentPositionStrokeWidth,
106
+ currentPositionRadius = FibonacciRetracement.defaultProps.currentPositionRadius,
107
+ retracements,
108
+ type,
109
+ } = this.props;
110
+
111
+ const { enabled, hoverText } = this.props;
112
+ const overrideIndex = isDefined(override) ? override.index : null;
113
+ const hoverTextWidthDefault = {
114
+ ...FibonacciRetracement.defaultProps.hoverText,
115
+ ...hoverText,
116
+ };
117
+
118
+ const currentRetracement =
119
+ isDefined(current) && isDefined(current.x2) ? (
120
+ <EachFibRetracement
121
+ interactive={false}
122
+ type={type}
123
+ appearance={appearance}
124
+ hoverText={hoverTextWidthDefault}
125
+ {...current}
126
+ onDoubleClick={(e) => this.handleDoubleClick(e, {}, 0)}
127
+ />
128
+ ) : null;
129
+ return (
130
+ <g>
131
+ {retracements.map((each, idx) => {
132
+ const eachAppearance = isDefined(each.appearance)
133
+ ? { ...appearance, ...each.appearance }
134
+ : appearance;
135
+
136
+ const eachHoverText = isDefined(each.hoverText)
137
+ ? { ...hoverTextWidthDefault, ...each.hoverText }
138
+ : hoverTextWidthDefault;
139
+
140
+ return (
141
+ <EachFibRetracement
142
+ key={idx}
143
+ ref={this.saveNodeType(idx)}
144
+ index={idx}
145
+ type={each.type}
146
+ selected={each.selected}
147
+ {...(idx === overrideIndex ? override : each)}
148
+ hoverText={eachHoverText}
149
+ appearance={eachAppearance}
150
+ onDrag={this.handleDrag}
151
+ onDragComplete={this.handleDragComplete}
152
+ onDoubleClick={(e, moreProps) => this.handleDoubleClick(e, moreProps, idx)}
153
+ onClickWhenHover={(e, moreProps) => this.handleClickWhenHover(e, moreProps, idx)}
154
+ onClickOutside={(e, moreProps) => this.handleClickOutside(e, moreProps, idx)}
155
+ onContextMenuWhenHover={(e, moreProps) => this.handleConextMenu(e, moreProps, idx)}
156
+ />
157
+ );
158
+ })}
159
+ {currentRetracement}
160
+ <MouseLocationIndicator
161
+ enabled={enabled}
162
+ snap={false}
163
+ r={currentPositionRadius}
164
+ stroke={currentPositionStroke}
165
+ opacity={currentPositionOpacity}
166
+ strokeWidth={currentPositionStrokeWidth}
167
+ onMouseDown={this.handleStart}
168
+ onClick={this.handleEnd}
169
+ onMouseMove={(e, xyValues) => this.handleDrawRetracement(e, xyValues)}
170
+ />
171
+ </g>
172
+ );
173
+ }
174
+
175
+ private readonly handleDoubleClick = (_: React.MouseEvent, moreProps: any, idx: any) => {
176
+ if (this.props.onDoubleClick) {
177
+ this.props.onDoubleClick(_, moreProps, idx);
178
+ }
179
+ };
180
+ private readonly handleClickWhenHover = (_: React.MouseEvent, moreProps: any, idx: any) => {
181
+ if (this.props.onClickWhenHover) {
182
+ this.props.onClickWhenHover(_, moreProps, idx);
183
+ }
184
+ };
185
+ private readonly handleClickOutside = (_: React.MouseEvent, moreProps: any, idx: any) => {
186
+ if (this.props.onClickOutside) {
187
+ this.props.onClickOutside(_, moreProps, idx);
188
+ }
189
+ };
190
+ private readonly handleConextMenu = (_: React.MouseEvent, moreProps: any, idx: any) => {
191
+ if (this.props.onConextMenu) {
192
+ _.stopPropagation();
193
+ _.preventDefault();
194
+ this.props.onConextMenu(_, moreProps, idx);
195
+ }
196
+ };
197
+
198
+ private readonly handleDrawRetracement = (_: React.MouseEvent, xyValue: any) => {
199
+ const { current } = this.state;
200
+ if (isDefined(current) && isDefined(current.x1)) {
201
+ this.mouseMoved = true;
202
+ this.setState({
203
+ current: {
204
+ ...current,
205
+ x2: xyValue[0],
206
+ y2: xyValue[1],
207
+ },
208
+ });
209
+ }
210
+ };
211
+
212
+ private readonly handleEdge1Drag = (_: React.MouseEvent, echo: any, newXYValue: any, origXYValue: any) => {
213
+ const { retracements } = this.props;
214
+ const { index } = echo;
215
+
216
+ const dx = origXYValue.x1Value - newXYValue.x1Value;
217
+
218
+ this.setState({
219
+ override: {
220
+ index,
221
+ x1: retracements[index].x1 - dx,
222
+ y1: retracements[index].y1,
223
+ x2: retracements[index].x2,
224
+ y2: retracements[index].y2,
225
+ },
226
+ });
227
+ };
228
+
229
+ private readonly handleDrag = (_: React.MouseEvent, index: any, xy: any) => {
230
+ this.setState({
231
+ override: {
232
+ index,
233
+ ...xy,
234
+ },
235
+ });
236
+ };
237
+
238
+ private readonly handleEdge2Drag = (_: React.MouseEvent, echo: any, newXYValue: any, origXYValue: any) => {
239
+ const { retracements } = this.props;
240
+ const { index } = echo;
241
+
242
+ const dx = origXYValue.x2Value - newXYValue.x2Value;
243
+
244
+ this.setState({
245
+ override: {
246
+ index,
247
+ x1: retracements[index].x1,
248
+ y1: retracements[index].y1,
249
+ x2: retracements[index].x2 - dx,
250
+ y2: retracements[index].y2,
251
+ },
252
+ });
253
+ };
254
+
255
+ private readonly handleDragComplete = (e: React.MouseEvent, moreProps: any) => {
256
+ const { retracements } = this.props;
257
+ const { override } = this.state;
258
+ if (isDefined(override)) {
259
+ const { index, ...rest } = override;
260
+
261
+ const newRetracements = retracements.map((each, idx) =>
262
+ idx === index ? { ...each, ...rest, selected: true } : each,
263
+ );
264
+ this.setState(
265
+ {
266
+ override: null,
267
+ },
268
+ () => {
269
+ const { onComplete } = this.props;
270
+ if (onComplete !== undefined) {
271
+ onComplete(e, newRetracements, moreProps);
272
+ }
273
+ },
274
+ );
275
+ }
276
+ };
277
+
278
+ private readonly handleStart = (e: React.MouseEvent, xyValue: any, moreProps: any) => {
279
+ const { current } = this.state;
280
+ if (isNotDefined(current) || isNotDefined(current.x1)) {
281
+ this.mouseMoved = false;
282
+ this.setState(
283
+ {
284
+ current: {
285
+ x1: xyValue[0],
286
+ y1: xyValue[1],
287
+ x2: null,
288
+ y2: null,
289
+ },
290
+ },
291
+ () => {
292
+ const { onStart } = this.props;
293
+ if (onStart !== undefined) {
294
+ onStart(moreProps);
295
+ }
296
+ },
297
+ );
298
+ }
299
+ };
300
+
301
+ private readonly handleEnd = (e: React.MouseEvent, xyValue: any, moreProps: any) => {
302
+ const { retracements, appearance, type } = this.props;
303
+ const { current } = this.state;
304
+
305
+ if (this.mouseMoved && isDefined(current) && isDefined(current.x1)) {
306
+ const newRetracements = retracements.concat({
307
+ ...current,
308
+ x2: xyValue[0],
309
+ y2: xyValue[1],
310
+ selected: true,
311
+ appearance,
312
+ type,
313
+ });
314
+
315
+ this.setState(
316
+ {
317
+ current: null,
318
+ },
319
+ () => {
320
+ const { onComplete } = this.props;
321
+ if (onComplete !== undefined) {
322
+ onComplete(e, newRetracements, moreProps);
323
+ }
324
+ },
325
+ );
326
+ }
327
+ };
328
+ }