@tradingaction/coordinates 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 (51) hide show
  1. package/LICENSE +24 -0
  2. package/README.md +5 -0
  3. package/lib/CrossHairCursor.d.ts +22 -0
  4. package/lib/CrossHairCursor.js +76 -0
  5. package/lib/CrossHairCursor.js.map +1 -0
  6. package/lib/CurrentCoordinate.d.ts +31 -0
  7. package/lib/CurrentCoordinate.js +54 -0
  8. package/lib/CurrentCoordinate.js.map +1 -0
  9. package/lib/Cursor.d.ts +31 -0
  10. package/lib/Cursor.js +122 -0
  11. package/lib/Cursor.js.map +1 -0
  12. package/lib/EdgeCoordinate.d.ts +32 -0
  13. package/lib/EdgeCoordinate.js +151 -0
  14. package/lib/EdgeCoordinate.js.map +1 -0
  15. package/lib/EdgeCoordinateV2.d.ts +3 -0
  16. package/lib/EdgeCoordinateV2.js +138 -0
  17. package/lib/EdgeCoordinateV2.js.map +1 -0
  18. package/lib/EdgeCoordinateV3.d.ts +3 -0
  19. package/lib/EdgeCoordinateV3.js +176 -0
  20. package/lib/EdgeCoordinateV3.js.map +1 -0
  21. package/lib/EdgeIndicator.d.ts +55 -0
  22. package/lib/EdgeIndicator.js +85 -0
  23. package/lib/EdgeIndicator.js.map +1 -0
  24. package/lib/MouseCoordinateX.d.ts +49 -0
  25. package/lib/MouseCoordinateX.js +85 -0
  26. package/lib/MouseCoordinateX.js.map +1 -0
  27. package/lib/MouseCoordinateXV2.d.ts +61 -0
  28. package/lib/MouseCoordinateXV2.js +92 -0
  29. package/lib/MouseCoordinateXV2.js.map +1 -0
  30. package/lib/MouseCoordinateY.d.ts +68 -0
  31. package/lib/MouseCoordinateY.js +91 -0
  32. package/lib/MouseCoordinateY.js.map +1 -0
  33. package/lib/PriceCoordinate.d.ts +53 -0
  34. package/lib/PriceCoordinate.js +81 -0
  35. package/lib/PriceCoordinate.js.map +1 -0
  36. package/lib/index.d.ts +8 -0
  37. package/lib/index.js +9 -0
  38. package/lib/index.js.map +1 -0
  39. package/package.json +49 -0
  40. package/src/CrossHairCursor.tsx +116 -0
  41. package/src/CurrentCoordinate.tsx +95 -0
  42. package/src/Cursor.tsx +174 -0
  43. package/src/EdgeCoordinate.tsx +239 -0
  44. package/src/EdgeCoordinateV2.tsx +204 -0
  45. package/src/EdgeCoordinateV3.tsx +284 -0
  46. package/src/EdgeIndicator.tsx +161 -0
  47. package/src/MouseCoordinateX.tsx +127 -0
  48. package/src/MouseCoordinateXV2.tsx +161 -0
  49. package/src/MouseCoordinateY.tsx +141 -0
  50. package/src/PriceCoordinate.tsx +121 -0
  51. package/src/index.ts +8 -0
@@ -0,0 +1,95 @@
1
+ import { getMouseCanvas, GenericChartComponent } from "@tradingaction/core";
2
+ import * as React from "react";
3
+
4
+ export interface CurrentCoordinateProps {
5
+ /**
6
+ * Fill style for the circle.
7
+ */
8
+ readonly fillStyle?: string | ((datum: any) => string);
9
+ /**
10
+ * The radius to draw the circle
11
+ */
12
+ readonly r: number;
13
+ /**
14
+ * Stroke of the circle
15
+ */
16
+ readonly strokeStyle?: string | ((datum: any) => string);
17
+ /**
18
+ * Y accessor to use for the circle.
19
+ */
20
+ readonly yAccessor: (item: any) => number;
21
+ }
22
+
23
+ /**
24
+ * Draws a circle at the current x location of radius `r`.
25
+ */
26
+ export class CurrentCoordinate extends React.Component<CurrentCoordinateProps> {
27
+ public static defaultProps = {
28
+ fillStyle: "#2196f3",
29
+ r: 3,
30
+ };
31
+
32
+ public render() {
33
+ return (
34
+ <GenericChartComponent
35
+ canvasDraw={this.drawOnCanvas}
36
+ canvasToDraw={getMouseCanvas}
37
+ drawOn={["mousemove", "pan"]}
38
+ />
39
+ );
40
+ }
41
+
42
+ private readonly drawOnCanvas = (ctx: CanvasRenderingContext2D, moreProps: any) => {
43
+ const circle = this.getCircle(moreProps);
44
+ if (circle === undefined) {
45
+ return;
46
+ }
47
+
48
+ const { fillStyle, r, strokeStyle } = this.props;
49
+
50
+ const fillColor = fillStyle instanceof Function ? fillStyle(moreProps.currentItem) : fillStyle;
51
+ if (fillColor !== undefined) {
52
+ ctx.fillStyle = fillColor;
53
+ }
54
+
55
+ const strokeColor = strokeStyle instanceof Function ? strokeStyle(moreProps.currentItem) : strokeStyle;
56
+ if (strokeColor !== undefined) {
57
+ ctx.strokeStyle = strokeColor;
58
+ }
59
+
60
+ ctx.beginPath();
61
+ ctx.arc(circle.x, circle.y, r, 0, 2 * Math.PI, false);
62
+ ctx.fill();
63
+ if (strokeColor !== undefined) {
64
+ ctx.stroke();
65
+ }
66
+ };
67
+
68
+ private readonly getCircle = (moreProps: any) => {
69
+ const {
70
+ show,
71
+ xScale,
72
+ chartConfig: { yScale },
73
+ currentItem,
74
+ xAccessor,
75
+ } = moreProps;
76
+
77
+ if (!show || currentItem === undefined) {
78
+ return undefined;
79
+ }
80
+
81
+ const { yAccessor } = this.props;
82
+
83
+ const xValue = xAccessor(currentItem);
84
+ const yValue = yAccessor(currentItem);
85
+
86
+ if (yValue === undefined) {
87
+ return undefined;
88
+ }
89
+
90
+ const x = Math.round(xScale(xValue));
91
+ const y = Math.round(yScale(yValue));
92
+
93
+ return { x, y };
94
+ };
95
+ }
package/src/Cursor.tsx ADDED
@@ -0,0 +1,174 @@
1
+ import {
2
+ ChartCanvasContext,
3
+ first,
4
+ GenericComponent,
5
+ getMouseCanvas,
6
+ getStrokeDasharrayCanvas,
7
+ last,
8
+ strokeDashTypes,
9
+ } from "@tradingaction/core";
10
+ import * as React from "react";
11
+
12
+ export interface CursorProps {
13
+ readonly customX?: (props: CursorProps, moreProps: any) => number;
14
+ readonly disableYCursor?: boolean;
15
+ readonly snapX?: boolean;
16
+ readonly strokeDasharray?: strokeDashTypes;
17
+ readonly strokeStyle?: string;
18
+ readonly useXCursorShape?: boolean;
19
+ readonly xCursorShapeFillStyle?: string | ((currentItem: any) => string);
20
+ readonly xCursorShapeStrokeStyle?: string | ((currentItem: any) => string);
21
+ readonly xCursorShapeStrokeDasharray?: strokeDashTypes;
22
+ }
23
+
24
+ const defaultCustomSnapX = (props: CursorProps, moreProps: any) => {
25
+ const { xScale, xAccessor, currentItem, mouseXY } = moreProps;
26
+ const { snapX } = props;
27
+ const x = snapX ? Math.round(xScale(xAccessor(currentItem))) : mouseXY[0];
28
+ return x;
29
+ };
30
+
31
+ export class Cursor extends React.Component<CursorProps> {
32
+ public static defaultProps = {
33
+ strokeStyle: "rgba(55, 71, 79, 0.8)",
34
+ strokeDasharray: "ShortDash",
35
+ snapX: true,
36
+ customX: defaultCustomSnapX,
37
+ disableYCursor: false,
38
+ useXCursorShape: false,
39
+ xCursorShapeStrokeStyle: "rgba(0, 0, 0, 0.5)",
40
+ };
41
+
42
+ public static contextType = ChartCanvasContext;
43
+
44
+ public render() {
45
+ return (
46
+ <GenericComponent
47
+ clip={false}
48
+ canvasDraw={this.drawOnCanvas}
49
+ canvasToDraw={getMouseCanvas}
50
+ drawOn={["mousemove", "pan", "drag"]}
51
+ />
52
+ );
53
+ }
54
+
55
+ private getXCursorShapeStroke({ currentItem }: any): string | undefined {
56
+ const { xCursorShapeStrokeStyle } = this.props;
57
+
58
+ return xCursorShapeStrokeStyle instanceof Function
59
+ ? xCursorShapeStrokeStyle(currentItem)
60
+ : xCursorShapeStrokeStyle;
61
+ }
62
+
63
+ private getXCursorShapeFill({ currentItem }: any): string | undefined {
64
+ const { xCursorShapeFillStyle } = this.props;
65
+
66
+ return xCursorShapeFillStyle instanceof Function ? xCursorShapeFillStyle(currentItem) : xCursorShapeFillStyle;
67
+ }
68
+
69
+ private getXCursorShape(moreProps: any) {
70
+ const { height, xScale, currentItem, plotData } = moreProps;
71
+ const { xAccessor } = moreProps;
72
+ const xValue = xAccessor(currentItem);
73
+ const centerX = xScale(xValue);
74
+ const shapeWidth =
75
+ Math.abs(xScale(xAccessor(last(plotData))) - xScale(xAccessor(first(plotData)))) / (plotData.length - 1);
76
+ const xPos = centerX - shapeWidth / 2;
77
+
78
+ return { height, xPos, shapeWidth };
79
+ }
80
+
81
+ private getXYCursor(props: CursorProps, moreProps: any) {
82
+ const { mouseXY, currentItem, show, height, width } = moreProps;
83
+
84
+ const { customX = Cursor.defaultProps.customX, strokeStyle, strokeDasharray, disableYCursor } = props;
85
+
86
+ if (!show || currentItem === undefined) {
87
+ return undefined;
88
+ }
89
+
90
+ const yCursor = {
91
+ x1: 0,
92
+ x2: width,
93
+ y1: mouseXY[1] + 0.5,
94
+ y2: mouseXY[1] + 0.5,
95
+ strokeStyle,
96
+ strokeDasharray,
97
+ isXCursor: false,
98
+ };
99
+
100
+ const x = customX(props, moreProps);
101
+
102
+ const xCursor = {
103
+ x1: x,
104
+ x2: x,
105
+ y1: 0,
106
+ y2: height,
107
+ strokeStyle,
108
+ strokeDasharray,
109
+ isXCursor: true,
110
+ };
111
+
112
+ return disableYCursor ? [xCursor] : [yCursor, xCursor];
113
+ }
114
+
115
+ private readonly drawOnCanvas = (ctx: CanvasRenderingContext2D, moreProps: any) => {
116
+ const cursors = this.getXYCursor(this.props, moreProps);
117
+ if (cursors === undefined) {
118
+ return;
119
+ }
120
+
121
+ const { useXCursorShape } = this.props;
122
+
123
+ const { margin, ratio } = this.context;
124
+
125
+ const originX = 0.5 * ratio + margin.left;
126
+ const originY = 0.5 * ratio + margin.top;
127
+
128
+ ctx.save();
129
+ ctx.setTransform(1, 0, 0, 1, 0, 0);
130
+ ctx.scale(ratio, ratio);
131
+ ctx.translate(originX, originY);
132
+
133
+ cursors.forEach((line) => {
134
+ if (useXCursorShape && line.isXCursor) {
135
+ const { xCursorShapeStrokeDasharray } = this.props;
136
+ if (xCursorShapeStrokeDasharray !== undefined) {
137
+ const xShapeStrokeStyle = this.getXCursorShapeStroke(moreProps);
138
+ if (xShapeStrokeStyle !== undefined) {
139
+ ctx.strokeStyle = xShapeStrokeStyle;
140
+ }
141
+ ctx.setLineDash(getStrokeDasharrayCanvas(xCursorShapeStrokeDasharray));
142
+ }
143
+
144
+ ctx.beginPath();
145
+ const xShapeFillStyle = this.getXCursorShapeFill(moreProps);
146
+ if (xShapeFillStyle !== undefined) {
147
+ ctx.fillStyle = xShapeFillStyle;
148
+ }
149
+
150
+ ctx.beginPath();
151
+
152
+ const xShape = this.getXCursorShape(moreProps);
153
+ xCursorShapeStrokeDasharray === undefined
154
+ ? ctx.fillRect(xShape.xPos, 0, xShape.shapeWidth, xShape.height)
155
+ : ctx.rect(xShape.xPos, 0, xShape.shapeWidth, xShape.height);
156
+ ctx.fill();
157
+ } else {
158
+ if (line.strokeStyle !== undefined) {
159
+ ctx.strokeStyle = line.strokeStyle;
160
+ }
161
+
162
+ const dashArray = getStrokeDasharrayCanvas(line.strokeDasharray);
163
+ ctx.setLineDash(dashArray);
164
+ ctx.beginPath();
165
+ ctx.moveTo(line.x1, line.y1);
166
+ ctx.lineTo(line.x2, line.y2);
167
+ }
168
+
169
+ ctx.stroke();
170
+ });
171
+
172
+ ctx.restore();
173
+ };
174
+ }
@@ -0,0 +1,239 @@
1
+ import * as React from "react";
2
+
3
+ const helper = (props: any) => {
4
+ const { coordinate: displayCoordinate, show, type, orient, edgeAt, hideLine } = props;
5
+ const { fill, fontFamily, fontSize, textFill, lineStroke, arrowWidth } = props;
6
+ const { rectWidth, rectHeight } = props;
7
+ const { x1, y1, x2, y2 } = props;
8
+
9
+ if (!show) {
10
+ return null;
11
+ }
12
+
13
+ let edgeXRect;
14
+ let edgeYRect;
15
+ let edgeXText;
16
+ let edgeYText;
17
+
18
+ if (type === "horizontal") {
19
+ edgeXRect = orient === "right" ? edgeAt + 1 : edgeAt - rectWidth - arrowWidth - 1;
20
+ edgeYRect = y1 - rectHeight / 2;
21
+ edgeXText = orient === "right" ? edgeAt + rectWidth / 2 + arrowWidth : edgeAt - rectWidth / 2 - arrowWidth;
22
+ edgeYText = y1;
23
+ } else {
24
+ edgeXRect = x1 - rectWidth / 2;
25
+ edgeYRect = orient === "bottom" ? edgeAt : edgeAt - rectHeight;
26
+ edgeXText = x1;
27
+ edgeYText = orient === "bottom" ? edgeAt + rectHeight / 2 : edgeAt - rectHeight / 2;
28
+ }
29
+
30
+ let coordinateBase;
31
+ let coordinate;
32
+ const textAnchor = "middle";
33
+ if (displayCoordinate !== undefined) {
34
+ coordinateBase = {
35
+ edgeXRect,
36
+ edgeYRect,
37
+ rectHeight,
38
+ rectWidth,
39
+ fill,
40
+ arrowWidth,
41
+ };
42
+ coordinate = {
43
+ edgeXText,
44
+ edgeYText,
45
+ textAnchor,
46
+ fontFamily,
47
+ fontSize,
48
+ textFill,
49
+ displayCoordinate,
50
+ };
51
+ }
52
+
53
+ const line = hideLine
54
+ ? undefined
55
+ : {
56
+ stroke: lineStroke,
57
+ x1,
58
+ y1,
59
+ x2,
60
+ y2,
61
+ };
62
+ return {
63
+ coordinateBase,
64
+ coordinate,
65
+ line,
66
+ orient,
67
+ };
68
+ };
69
+
70
+ export interface EdgeCoordinateProps {
71
+ readonly className?: string;
72
+ readonly type: "vertical" | "horizontal";
73
+ readonly coordinate?: any;
74
+ readonly x1: number;
75
+ readonly y1: number;
76
+ readonly x2: number;
77
+ readonly y2: number;
78
+ readonly orient?: "bottom" | "top" | "left" | "right";
79
+ readonly rectWidth?: number;
80
+ readonly hideLine?: boolean;
81
+ readonly fill?: string;
82
+ readonly fontFamily: string;
83
+ readonly fontSize: number;
84
+ readonly lineStroke?: string;
85
+ }
86
+
87
+ export class EdgeCoordinate extends React.Component<EdgeCoordinateProps> {
88
+ public static defaultProps = {
89
+ className: "react-financial-charts-edgecoordinate",
90
+ orient: "left",
91
+ hideLine: false,
92
+ fill: "#8a8a8a",
93
+ fontFamily: "-apple-system, system-ui, Roboto, 'Helvetica Neue', Ubuntu, sans-serif",
94
+ fontSize: 13,
95
+ textFill: "#FFFFFF",
96
+ lineStroke: "rgba(0, 0, 0, 0.3)",
97
+ arrowWidth: 10,
98
+ };
99
+
100
+ public static drawOnCanvasStatic = (ctx: CanvasRenderingContext2D, props: any) => {
101
+ props = { ...EdgeCoordinate.defaultProps, ...props };
102
+
103
+ const edge = helper(props);
104
+ if (edge === null) {
105
+ return;
106
+ }
107
+
108
+ if (edge.coordinate !== undefined && edge.coordinateBase !== undefined) {
109
+ const { rectWidth, rectHeight, arrowWidth } = edge.coordinateBase;
110
+
111
+ ctx.fillStyle = edge.coordinateBase.fill;
112
+
113
+ const x = edge.coordinateBase.edgeXRect;
114
+ const y = edge.coordinateBase.edgeYRect;
115
+
116
+ ctx.beginPath();
117
+
118
+ if (edge.orient === "right") {
119
+ ctx.moveTo(x, y + rectHeight / 2);
120
+ ctx.lineTo(x + arrowWidth, y);
121
+ ctx.lineTo(x + rectWidth + arrowWidth, y);
122
+ ctx.lineTo(x + rectWidth + arrowWidth, y + rectHeight);
123
+ ctx.lineTo(x + arrowWidth, y + rectHeight);
124
+ ctx.closePath();
125
+ } else if (edge.orient === "left") {
126
+ ctx.moveTo(x, y);
127
+ ctx.lineTo(x + rectWidth, y);
128
+ ctx.lineTo(x + rectWidth + arrowWidth, y + rectHeight / 2);
129
+ ctx.lineTo(x + rectWidth, y + rectHeight);
130
+ ctx.lineTo(x, y + rectHeight);
131
+ ctx.closePath();
132
+ } else {
133
+ ctx.rect(x, y, rectWidth, rectHeight);
134
+ }
135
+ ctx.fill();
136
+
137
+ ctx.font = `${edge.coordinate.fontSize}px ${edge.coordinate.fontFamily}`;
138
+ ctx.fillStyle = edge.coordinate.textFill;
139
+ ctx.textAlign =
140
+ edge.coordinate.textAnchor === "middle" ? "center" : (edge.coordinate.textAnchor as CanvasTextAlign);
141
+ ctx.textBaseline = "middle";
142
+
143
+ ctx.fillText(edge.coordinate.displayCoordinate, edge.coordinate.edgeXText, edge.coordinate.edgeYText);
144
+ }
145
+
146
+ if (edge.line !== undefined) {
147
+ ctx.strokeStyle = edge.line.stroke;
148
+
149
+ ctx.beginPath();
150
+ ctx.moveTo(edge.line.x1, edge.line.y1);
151
+ ctx.lineTo(edge.line.x2, edge.line.y2);
152
+ ctx.stroke();
153
+ }
154
+ };
155
+
156
+ public render() {
157
+ const { className } = this.props;
158
+
159
+ const edge = helper(this.props);
160
+ if (edge === null) {
161
+ return null;
162
+ }
163
+ let line;
164
+ let coordinateBase;
165
+ let coordinate;
166
+
167
+ if (edge.line !== undefined) {
168
+ line = (
169
+ <line
170
+ className="react-financial-charts-cross-hair"
171
+ stroke={edge.line.stroke}
172
+ x1={edge.line.x1}
173
+ y1={edge.line.y1}
174
+ x2={edge.line.x2}
175
+ y2={edge.line.y2}
176
+ />
177
+ );
178
+ }
179
+
180
+ if (edge.coordinate !== undefined && edge.coordinateBase !== undefined) {
181
+ const { rectWidth, rectHeight, arrowWidth } = edge.coordinateBase;
182
+
183
+ const path =
184
+ edge.orient === "left"
185
+ ? `M0,0L0,${rectHeight}L${rectWidth},${rectHeight}L${
186
+ rectWidth + arrowWidth
187
+ },10L${rectWidth},0L0,0L0,0`
188
+ : `M0,${arrowWidth}L${arrowWidth},${rectHeight}L${rectWidth + arrowWidth},${rectHeight}L${
189
+ rectWidth + arrowWidth
190
+ },0L${arrowWidth},0L0,${arrowWidth}`;
191
+
192
+ coordinateBase =
193
+ edge.orient === "left" || edge.orient === "right" ? (
194
+ <g transform={`translate(${edge.coordinateBase.edgeXRect},${edge.coordinateBase.edgeYRect})`}>
195
+ <path
196
+ d={path}
197
+ key={1}
198
+ className="react-financial-charts-text-background"
199
+ height={rectHeight}
200
+ width={rectWidth}
201
+ fill={edge.coordinateBase.fill}
202
+ />
203
+ </g>
204
+ ) : (
205
+ <rect
206
+ key={1}
207
+ className="react-financial-charts-text-background"
208
+ x={edge.coordinateBase.edgeXRect}
209
+ y={edge.coordinateBase.edgeYRect}
210
+ height={rectHeight}
211
+ width={rectWidth}
212
+ fill={edge.coordinateBase.fill}
213
+ />
214
+ );
215
+
216
+ coordinate = (
217
+ <text
218
+ key={2}
219
+ x={edge.coordinate.edgeXText}
220
+ y={edge.coordinate.edgeYText}
221
+ textAnchor={edge.coordinate.textAnchor}
222
+ fontFamily={edge.coordinate.fontFamily}
223
+ fontSize={edge.coordinate.fontSize}
224
+ dy=".32em"
225
+ fill={edge.coordinate.textFill}
226
+ >
227
+ {edge.coordinate.displayCoordinate}
228
+ </text>
229
+ );
230
+ }
231
+ return (
232
+ <g className={className}>
233
+ {line}
234
+ {coordinateBase}
235
+ {coordinate}
236
+ </g>
237
+ );
238
+ }
239
+ }
@@ -0,0 +1,204 @@
1
+ import * as React from "react";
2
+
3
+ export function renderSVG(props: any) {
4
+ const { className } = props;
5
+
6
+ const edge = helper(props);
7
+ if (edge === null) {
8
+ return null;
9
+ }
10
+ let line;
11
+ let coordinateBase;
12
+ let coordinate;
13
+
14
+ if (edge.line !== undefined) {
15
+ line = (
16
+ <line
17
+ className="react-financial-charts-cross-hair"
18
+ stroke={edge.line.stroke}
19
+ x1={edge.line.x1}
20
+ y1={edge.line.y1}
21
+ x2={edge.line.x2}
22
+ y2={edge.line.y2}
23
+ />
24
+ );
25
+ }
26
+
27
+ if (edge.coordinate !== undefined && edge.coordinateBase !== undefined) {
28
+ const { rectWidth, rectHeight, arrowWidth } = edge.coordinateBase;
29
+
30
+ const path =
31
+ edge.orient === "left"
32
+ ? `M0,0L0,${rectHeight}L${rectWidth},${rectHeight}L${rectWidth + arrowWidth},10L${rectWidth},0L0,0L0,0`
33
+ : `M0,${arrowWidth}L${arrowWidth},${rectHeight}L${rectWidth + arrowWidth},${rectHeight}L${
34
+ rectWidth + arrowWidth
35
+ },0L${arrowWidth},0L0,${arrowWidth}`;
36
+
37
+ coordinateBase =
38
+ edge.orient === "left" || edge.orient === "right" ? (
39
+ <g transform={`translate(${edge.coordinateBase.edgeXRect},${edge.coordinateBase.edgeYRect})`}>
40
+ <path
41
+ d={path}
42
+ key={1}
43
+ className="react-financial-charts-text-background"
44
+ height={rectHeight}
45
+ width={rectWidth}
46
+ fill={edge.coordinateBase.fill}
47
+ />
48
+ </g>
49
+ ) : (
50
+ <rect
51
+ key={1}
52
+ className="react-financial-charts-text-background"
53
+ x={edge.coordinateBase.edgeXRect}
54
+ y={edge.coordinateBase.edgeYRect}
55
+ height={rectHeight}
56
+ width={rectWidth}
57
+ fill={edge.coordinateBase.fill}
58
+ />
59
+ );
60
+
61
+ coordinate = (
62
+ <text
63
+ key={2}
64
+ x={edge.coordinate.edgeXText}
65
+ y={edge.coordinate.edgeYText}
66
+ textAnchor={edge.coordinate.textAnchor}
67
+ fontFamily={edge.coordinate.fontFamily}
68
+ fontSize={edge.coordinate.fontSize}
69
+ dy=".32em"
70
+ fill={edge.coordinate.textFill}
71
+ >
72
+ {edge.coordinate.displayCoordinate}
73
+ </text>
74
+ );
75
+ }
76
+ return (
77
+ <g className={className}>
78
+ {line}
79
+ {coordinateBase}
80
+ {coordinate}
81
+ </g>
82
+ );
83
+ }
84
+
85
+ function helper(props: any) {
86
+ const { coordinate: displayCoordinate, show, type, orient, edgeAt, hideLine } = props;
87
+ const { fill, fontFamily, fontSize, textFill, lineStroke, arrowWidth } = props;
88
+ const { rectWidth, rectHeight } = props;
89
+ const { x1, y1, x2, y2, dx } = props;
90
+
91
+ if (!show) {
92
+ return null;
93
+ }
94
+
95
+ let edgeXRect;
96
+ let edgeYRect;
97
+ let edgeXText;
98
+ let edgeYText;
99
+
100
+ if (type === "horizontal") {
101
+ edgeXRect = dx + (orient === "right" ? edgeAt + 1 : edgeAt - rectWidth - arrowWidth - 1);
102
+ edgeYRect = y1 - rectHeight / 2;
103
+ edgeXText =
104
+ dx + (orient === "right" ? edgeAt + rectWidth / 2 + arrowWidth : edgeAt - rectWidth / 2 - arrowWidth);
105
+ edgeYText = y1;
106
+ } else {
107
+ edgeXRect = x1 - rectWidth / 2;
108
+ edgeYRect = orient === "bottom" ? edgeAt : edgeAt - rectHeight;
109
+ edgeXText = x1;
110
+ edgeYText = orient === "bottom" ? edgeAt + rectHeight / 2 : edgeAt - rectHeight / 2;
111
+ }
112
+ let coordinateBase;
113
+ let coordinate;
114
+ const textAnchor = "middle";
115
+ if (displayCoordinate !== undefined) {
116
+ coordinateBase = {
117
+ edgeXRect,
118
+ edgeYRect,
119
+ rectHeight,
120
+ rectWidth,
121
+ fill,
122
+ arrowWidth,
123
+ };
124
+ coordinate = {
125
+ edgeXText,
126
+ edgeYText,
127
+ textAnchor,
128
+ fontFamily,
129
+ fontSize,
130
+ textFill,
131
+ displayCoordinate,
132
+ };
133
+ }
134
+
135
+ const line = hideLine
136
+ ? undefined
137
+ : {
138
+ stroke: lineStroke,
139
+ x1,
140
+ y1,
141
+ x2,
142
+ y2,
143
+ };
144
+ return {
145
+ coordinateBase,
146
+ coordinate,
147
+ line,
148
+ orient,
149
+ };
150
+ }
151
+
152
+ export function drawOnCanvas(ctx: CanvasRenderingContext2D, props: any) {
153
+ const edge = helper(props);
154
+
155
+ if (edge === null) {
156
+ return;
157
+ }
158
+
159
+ if (edge.coordinate !== undefined && edge.coordinateBase !== undefined) {
160
+ const { rectWidth, rectHeight, arrowWidth } = edge.coordinateBase;
161
+
162
+ ctx.fillStyle = edge.coordinateBase.fill;
163
+
164
+ const x = edge.coordinateBase.edgeXRect;
165
+ const y = edge.coordinateBase.edgeYRect;
166
+
167
+ ctx.beginPath();
168
+
169
+ if (edge.orient === "right") {
170
+ ctx.moveTo(x, y + rectHeight / 2);
171
+ ctx.lineTo(x + arrowWidth, y);
172
+ ctx.lineTo(x + rectWidth + arrowWidth, y);
173
+ ctx.lineTo(x + rectWidth + arrowWidth, y + rectHeight);
174
+ ctx.lineTo(x + arrowWidth, y + rectHeight);
175
+ ctx.closePath();
176
+ } else if (edge.orient === "left") {
177
+ ctx.moveTo(x, y);
178
+ ctx.lineTo(x + rectWidth, y);
179
+ ctx.lineTo(x + rectWidth + arrowWidth, y + rectHeight / 2);
180
+ ctx.lineTo(x + rectWidth, y + rectHeight);
181
+ ctx.lineTo(x, y + rectHeight);
182
+ ctx.closePath();
183
+ } else {
184
+ ctx.rect(x, y, rectWidth, rectHeight);
185
+ }
186
+ ctx.fill();
187
+
188
+ ctx.font = `${edge.coordinate.fontSize}px ${edge.coordinate.fontFamily}`;
189
+ ctx.fillStyle = edge.coordinate.textFill;
190
+ ctx.textAlign =
191
+ edge.coordinate.textAnchor === "middle" ? "center" : (edge.coordinate.textAnchor as CanvasTextAlign);
192
+ ctx.textBaseline = "middle";
193
+
194
+ ctx.fillText(edge.coordinate.displayCoordinate, edge.coordinate.edgeXText, edge.coordinate.edgeYText);
195
+ }
196
+ if (edge.line !== undefined) {
197
+ ctx.strokeStyle = edge.line.stroke;
198
+
199
+ ctx.beginPath();
200
+ ctx.moveTo(edge.line.x1, edge.line.y1);
201
+ ctx.lineTo(edge.line.x2, edge.line.y2);
202
+ ctx.stroke();
203
+ }
204
+ }