@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.
- package/LICENSE +24 -0
- package/README.md +5 -0
- package/lib/CrossHairCursor.d.ts +22 -0
- package/lib/CrossHairCursor.js +76 -0
- package/lib/CrossHairCursor.js.map +1 -0
- package/lib/CurrentCoordinate.d.ts +31 -0
- package/lib/CurrentCoordinate.js +54 -0
- package/lib/CurrentCoordinate.js.map +1 -0
- package/lib/Cursor.d.ts +31 -0
- package/lib/Cursor.js +122 -0
- package/lib/Cursor.js.map +1 -0
- package/lib/EdgeCoordinate.d.ts +32 -0
- package/lib/EdgeCoordinate.js +151 -0
- package/lib/EdgeCoordinate.js.map +1 -0
- package/lib/EdgeCoordinateV2.d.ts +3 -0
- package/lib/EdgeCoordinateV2.js +138 -0
- package/lib/EdgeCoordinateV2.js.map +1 -0
- package/lib/EdgeCoordinateV3.d.ts +3 -0
- package/lib/EdgeCoordinateV3.js +176 -0
- package/lib/EdgeCoordinateV3.js.map +1 -0
- package/lib/EdgeIndicator.d.ts +55 -0
- package/lib/EdgeIndicator.js +85 -0
- package/lib/EdgeIndicator.js.map +1 -0
- package/lib/MouseCoordinateX.d.ts +49 -0
- package/lib/MouseCoordinateX.js +85 -0
- package/lib/MouseCoordinateX.js.map +1 -0
- package/lib/MouseCoordinateXV2.d.ts +61 -0
- package/lib/MouseCoordinateXV2.js +92 -0
- package/lib/MouseCoordinateXV2.js.map +1 -0
- package/lib/MouseCoordinateY.d.ts +68 -0
- package/lib/MouseCoordinateY.js +91 -0
- package/lib/MouseCoordinateY.js.map +1 -0
- package/lib/PriceCoordinate.d.ts +53 -0
- package/lib/PriceCoordinate.js +81 -0
- package/lib/PriceCoordinate.js.map +1 -0
- package/lib/index.d.ts +8 -0
- package/lib/index.js +9 -0
- package/lib/index.js.map +1 -0
- package/package.json +49 -0
- package/src/CrossHairCursor.tsx +116 -0
- package/src/CurrentCoordinate.tsx +95 -0
- package/src/Cursor.tsx +174 -0
- package/src/EdgeCoordinate.tsx +239 -0
- package/src/EdgeCoordinateV2.tsx +204 -0
- package/src/EdgeCoordinateV3.tsx +284 -0
- package/src/EdgeIndicator.tsx +161 -0
- package/src/MouseCoordinateX.tsx +127 -0
- package/src/MouseCoordinateXV2.tsx +161 -0
- package/src/MouseCoordinateY.tsx +141 -0
- package/src/PriceCoordinate.tsx +121 -0
- 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
|
+
}
|