@tradingaction/tooltip 2.1.0 → 2.1.1
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/lib/IndicatorDisplayTooltip.d.ts +64 -0
- package/lib/IndicatorDisplayTooltip.js +202 -0
- package/lib/IndicatorDisplayTooltip.js.map +1 -0
- package/lib/index.d.ts +1 -0
- package/lib/index.js +1 -0
- package/lib/index.js.map +1 -1
- package/package.json +2 -2
- package/src/IndicatorDisplayTooltip.tsx +460 -0
- package/src/index.ts +1 -0
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
export interface IndicatorToolbarIcon {
|
|
3
|
+
readonly id: "eye" | "settings" | "code" | "delete" | "more";
|
|
4
|
+
readonly unicode: string;
|
|
5
|
+
readonly onClick: (option: IIndicatorDisplay) => void;
|
|
6
|
+
readonly size?: number;
|
|
7
|
+
readonly fillColor?: string;
|
|
8
|
+
readonly title?: string;
|
|
9
|
+
}
|
|
10
|
+
export interface MultiValueAccessor {
|
|
11
|
+
readonly label: string;
|
|
12
|
+
readonly accessor: (data: any) => number;
|
|
13
|
+
readonly fill?: string;
|
|
14
|
+
readonly showLabel?: boolean;
|
|
15
|
+
}
|
|
16
|
+
export interface IIndicatorDisplay {
|
|
17
|
+
readonly data?: any;
|
|
18
|
+
readonly yAccessor?: (data: any) => number;
|
|
19
|
+
readonly yAccessors?: MultiValueAccessor[];
|
|
20
|
+
readonly type: string;
|
|
21
|
+
readonly stroke: string;
|
|
22
|
+
readonly windowSize?: number;
|
|
23
|
+
readonly displayName?: string;
|
|
24
|
+
readonly icons?: IndicatorToolbarIcon[];
|
|
25
|
+
readonly orientation?: "vertical" | "horizontal";
|
|
26
|
+
readonly fillColor?: string;
|
|
27
|
+
readonly labelFill?: string;
|
|
28
|
+
readonly textFill?: string;
|
|
29
|
+
readonly fontFamily?: string;
|
|
30
|
+
readonly fontSize?: number;
|
|
31
|
+
readonly fontWeight?: number;
|
|
32
|
+
readonly showAccessorLabels?: boolean;
|
|
33
|
+
readonly alwaysShowFill?: boolean;
|
|
34
|
+
}
|
|
35
|
+
export interface IndicatorDisplayTooltipProps {
|
|
36
|
+
readonly className?: string;
|
|
37
|
+
readonly displayFormat: (value: number) => string;
|
|
38
|
+
readonly origin: number[];
|
|
39
|
+
readonly displayInit?: string;
|
|
40
|
+
readonly displayValuesFor?: (props: IndicatorDisplayTooltipProps, moreProps: any) => any;
|
|
41
|
+
readonly onClick?: (event: React.MouseEvent<SVGGElement, MouseEvent>) => void;
|
|
42
|
+
readonly onIconClick?: (event: React.MouseEvent<SVGTSpanElement, MouseEvent>, icon: IndicatorToolbarIcon) => void;
|
|
43
|
+
readonly textFill?: string;
|
|
44
|
+
readonly labelFill?: string;
|
|
45
|
+
readonly fontFamily?: string;
|
|
46
|
+
readonly fontSize?: number;
|
|
47
|
+
readonly fontWeight?: number;
|
|
48
|
+
readonly width?: number;
|
|
49
|
+
readonly options: IIndicatorDisplay[];
|
|
50
|
+
}
|
|
51
|
+
export declare class IndicatorDisplayTooltip extends React.Component<IndicatorDisplayTooltipProps> {
|
|
52
|
+
static defaultProps: {
|
|
53
|
+
className: string;
|
|
54
|
+
displayFormat: (n: number | {
|
|
55
|
+
valueOf(): number;
|
|
56
|
+
}) => string;
|
|
57
|
+
displayInit: string;
|
|
58
|
+
displayValuesFor: (_: any, props: any) => any;
|
|
59
|
+
origin: number[];
|
|
60
|
+
width: number;
|
|
61
|
+
};
|
|
62
|
+
render(): React.JSX.Element;
|
|
63
|
+
private readonly renderSVG;
|
|
64
|
+
}
|
|
@@ -0,0 +1,202 @@
|
|
|
1
|
+
import { functor, GenericChartComponent, last } from "@tradingaction/core";
|
|
2
|
+
import { format } from "d3-format";
|
|
3
|
+
import * as React from "react";
|
|
4
|
+
import { ToolTipText } from "./ToolTipText";
|
|
5
|
+
class SingleIndicatorDisplay extends React.Component {
|
|
6
|
+
constructor(props) {
|
|
7
|
+
super(props);
|
|
8
|
+
this.gRef = React.createRef();
|
|
9
|
+
this.handleMouseEnter = () => {
|
|
10
|
+
this.setState({ isHovered: true });
|
|
11
|
+
};
|
|
12
|
+
this.handleMouseLeave = () => {
|
|
13
|
+
this.setState({ isHovered: false });
|
|
14
|
+
};
|
|
15
|
+
this.handleIconClick = (e, icon) => {
|
|
16
|
+
e.stopPropagation();
|
|
17
|
+
if (this.props.onIconClick) {
|
|
18
|
+
this.props.onIconClick(e, icon);
|
|
19
|
+
}
|
|
20
|
+
if (typeof icon.onClick === "function") {
|
|
21
|
+
icon.onClick(this.props.options);
|
|
22
|
+
}
|
|
23
|
+
};
|
|
24
|
+
this.onClick = (event) => {
|
|
25
|
+
const { onClick, forChart, options } = this.props;
|
|
26
|
+
if (onClick !== undefined) {
|
|
27
|
+
onClick(event, Object.assign({ chartId: forChart }, options));
|
|
28
|
+
}
|
|
29
|
+
};
|
|
30
|
+
this.state = {
|
|
31
|
+
isHovered: false,
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
render() {
|
|
35
|
+
var _a, _b;
|
|
36
|
+
const { color, displayName, fontSize, fontFamily, fontWeight, textFill, labelFill, value, multiValues, origin, options, } = this.props;
|
|
37
|
+
const { isHovered } = this.state;
|
|
38
|
+
const translate = `translate(${origin[0]}, ${origin[1]})`;
|
|
39
|
+
const indicators = options.icons || [];
|
|
40
|
+
const orientation = options.orientation || "vertical";
|
|
41
|
+
// Use option-specific colors and fonts if provided, otherwise fall back to props
|
|
42
|
+
const effectiveLabelFill = options.labelFill || labelFill;
|
|
43
|
+
const effectiveTextFill = options.textFill || textFill;
|
|
44
|
+
const effectiveFontFamily = options.fontFamily || fontFamily;
|
|
45
|
+
const effectiveFontSize = (_a = options.fontSize) !== null && _a !== void 0 ? _a : fontSize;
|
|
46
|
+
const effectiveFontWeight = (_b = options.fontWeight) !== null && _b !== void 0 ? _b : fontWeight;
|
|
47
|
+
// Calculate dimensions based on orientation
|
|
48
|
+
let baseWidth = 200;
|
|
49
|
+
let baseHeight = 32;
|
|
50
|
+
let expandedWidth = isHovered ? 280 : 200;
|
|
51
|
+
let horizontalContentWidth = 0;
|
|
52
|
+
let displayNameWidth = 0;
|
|
53
|
+
if (multiValues && multiValues.length > 0) {
|
|
54
|
+
if (orientation === "vertical") {
|
|
55
|
+
// Vertical: height increases, width stays same
|
|
56
|
+
baseHeight = 32 + multiValues.length * 16;
|
|
57
|
+
expandedWidth = isHovered ? 280 : 200;
|
|
58
|
+
}
|
|
59
|
+
else {
|
|
60
|
+
// Horizontal: calculate actual width based on visible labels and display name
|
|
61
|
+
const fontSize = effectiveFontSize || 12;
|
|
62
|
+
const charWidth = fontSize * 0.55; // Approximate character width for monospace/sans-serif
|
|
63
|
+
// Calculate display name width
|
|
64
|
+
displayNameWidth = displayName.length * charWidth + 10; // 10px after name
|
|
65
|
+
// Calculate values width
|
|
66
|
+
horizontalContentWidth = 0;
|
|
67
|
+
multiValues.forEach((multiValue, idx) => {
|
|
68
|
+
const showLabel = multiValue.showLabel !== undefined ? multiValue.showLabel : (options.showAccessorLabels === true);
|
|
69
|
+
if (showLabel) {
|
|
70
|
+
// Label width: "Label: "
|
|
71
|
+
const labelText = `${multiValue.label}: `;
|
|
72
|
+
horizontalContentWidth += labelText.length * charWidth;
|
|
73
|
+
}
|
|
74
|
+
// Value width
|
|
75
|
+
const valueWidth = multiValue.value.length * charWidth;
|
|
76
|
+
horizontalContentWidth += valueWidth;
|
|
77
|
+
// Margin between values
|
|
78
|
+
if (idx < multiValues.length - 1) {
|
|
79
|
+
horizontalContentWidth += 8; // 8px margin between values
|
|
80
|
+
}
|
|
81
|
+
});
|
|
82
|
+
baseWidth = 20 + displayNameWidth + horizontalContentWidth; // 20px left padding + name + values
|
|
83
|
+
expandedWidth = isHovered ? baseWidth + 100 : baseWidth;
|
|
84
|
+
baseHeight = 25; // Reduced from 32 for tighter horizontal layout
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
return (React.createElement("g", { ref: this.gRef, transform: translate, onClick: this.onClick, onMouseEnter: this.handleMouseEnter, onMouseLeave: this.handleMouseLeave, style: { cursor: "pointer" } },
|
|
88
|
+
React.createElement("rect", { x: 0, y: 0, width: expandedWidth, height: baseHeight, fill: options.alwaysShowFill ? (options.fillColor || "#dbdfe4") : (isHovered ? (options.fillColor || "#dbdfe4") : "transparent"), stroke: color, strokeWidth: 1, rx: 4, style: { transition: "width 0.2s ease" } }),
|
|
89
|
+
React.createElement("rect", { x: 0, y: 0, width: 3, height: baseHeight, fill: color, rx: 2 }),
|
|
90
|
+
(!multiValues || multiValues.length === 0) && (React.createElement(ToolTipText, { x: 10, y: 18, fontFamily: effectiveFontFamily, fontSize: effectiveFontSize, fontWeight: effectiveFontWeight },
|
|
91
|
+
React.createElement("tspan", { fill: effectiveLabelFill, fontWeight: effectiveFontWeight, fontSize: effectiveFontSize || 12 }, displayName),
|
|
92
|
+
React.createElement("tspan", { x: 10, dy: 0, fill: effectiveTextFill, fontSize: effectiveFontSize || 12 }, "\u00A0"),
|
|
93
|
+
React.createElement("tspan", { fill: effectiveTextFill, fontSize: effectiveFontSize || 12 }, value))),
|
|
94
|
+
multiValues && multiValues.length > 0 && (React.createElement("g", null,
|
|
95
|
+
orientation === "horizontal" && (React.createElement("text", { x: 10, y: 17, fontFamily: effectiveFontFamily, fontSize: effectiveFontSize || 12, fill: effectiveLabelFill, fontWeight: effectiveFontWeight }, displayName)),
|
|
96
|
+
orientation === "vertical" ? (
|
|
97
|
+
// Vertical layout - display name + colon before values
|
|
98
|
+
React.createElement(React.Fragment, null,
|
|
99
|
+
React.createElement("text", { x: 10, y: 17, fontFamily: effectiveFontFamily, fontSize: effectiveFontSize || 12, fill: effectiveLabelFill, fontWeight: effectiveFontWeight }, displayName),
|
|
100
|
+
multiValues.map((multiValue, idx) => {
|
|
101
|
+
const showLabel = multiValue.showLabel !== undefined ? multiValue.showLabel : (options.showAccessorLabels === true);
|
|
102
|
+
return (React.createElement("text", { key: `multi-${idx}`, x: 10, y: 17 + (idx + 1) * 16, fontFamily: effectiveFontFamily, fontSize: effectiveFontSize || 12, fill: multiValue.fill || effectiveTextFill },
|
|
103
|
+
showLabel && (React.createElement("tspan", { fontWeight: effectiveFontWeight, fill: effectiveLabelFill },
|
|
104
|
+
multiValue.label,
|
|
105
|
+
":\u00A0")),
|
|
106
|
+
React.createElement("tspan", { fill: multiValue.fill || effectiveTextFill }, multiValue.value)));
|
|
107
|
+
}))) : (
|
|
108
|
+
// Horizontal layout - position based on actual content width
|
|
109
|
+
(() => {
|
|
110
|
+
const fontSize = effectiveFontSize || 12;
|
|
111
|
+
const charWidth = fontSize * 0.55;
|
|
112
|
+
const calcDisplayNameWidth = displayName.length * charWidth + 5;
|
|
113
|
+
let cumulativeX = 0 + calcDisplayNameWidth; // Start after display name
|
|
114
|
+
return multiValues.map((multiValue, idx) => {
|
|
115
|
+
const showLabel = multiValue.showLabel !== undefined ? multiValue.showLabel : (options.showAccessorLabels === true);
|
|
116
|
+
const x = cumulativeX;
|
|
117
|
+
// Calculate width for next position
|
|
118
|
+
if (showLabel) {
|
|
119
|
+
const labelText = `${multiValue.label}: `;
|
|
120
|
+
cumulativeX += labelText.length * charWidth;
|
|
121
|
+
}
|
|
122
|
+
cumulativeX += multiValue.value.length * charWidth;
|
|
123
|
+
// Add margin between values
|
|
124
|
+
if (idx < multiValues.length - 1) {
|
|
125
|
+
cumulativeX += 8;
|
|
126
|
+
}
|
|
127
|
+
return (React.createElement("text", { key: `multi-${idx}`, x: x, y: 17, fontFamily: effectiveFontFamily, fontSize: effectiveFontSize || 12, fill: multiValue.fill || effectiveTextFill },
|
|
128
|
+
showLabel && (React.createElement("tspan", { fontWeight: effectiveFontWeight, fill: effectiveLabelFill, fontSize: (effectiveFontSize || 12) - 1 },
|
|
129
|
+
multiValue.label,
|
|
130
|
+
":\u00A0")),
|
|
131
|
+
React.createElement("tspan", { fill: multiValue.fill || effectiveTextFill }, multiValue.value)));
|
|
132
|
+
});
|
|
133
|
+
})()))),
|
|
134
|
+
isHovered && indicators.length > 0 && (React.createElement("g", null, indicators.map((icon, idx) => {
|
|
135
|
+
let iconX;
|
|
136
|
+
if (orientation === "horizontal" && multiValues && multiValues.length > 0) {
|
|
137
|
+
// Position after calculated content width with spacing
|
|
138
|
+
iconX = 20 + displayNameWidth + horizontalContentWidth + 10 + idx * 16;
|
|
139
|
+
}
|
|
140
|
+
else {
|
|
141
|
+
// Position for vertical or single value
|
|
142
|
+
iconX = 210 + idx * 16;
|
|
143
|
+
}
|
|
144
|
+
return (React.createElement("g", { key: icon.id, onClick: (e) => this.handleIconClick(e, icon) },
|
|
145
|
+
icon.title && React.createElement("title", null, icon.title),
|
|
146
|
+
React.createElement("text", { x: iconX, y: 17, fontSize: icon.size || 14, fill: icon.fillColor || "#9ca3af", style: {
|
|
147
|
+
cursor: "pointer",
|
|
148
|
+
userSelect: "none",
|
|
149
|
+
transition: "fill 0.2s ease",
|
|
150
|
+
pointerEvents: "auto",
|
|
151
|
+
}, onMouseEnter: (e) => (e.target.style.fill = "#fff"), onMouseLeave: (e) => (e.target.style.fill = icon.fillColor || "#9ca3af") }, icon.unicode)));
|
|
152
|
+
})))));
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
// tslint:disable-next-line: max-classes-per-file
|
|
156
|
+
export class IndicatorDisplayTooltip extends React.Component {
|
|
157
|
+
constructor() {
|
|
158
|
+
super(...arguments);
|
|
159
|
+
this.renderSVG = (moreProps) => {
|
|
160
|
+
var _a;
|
|
161
|
+
const { chartId, chartConfig, chartConfig: { height = 0 } = {}, fullData } = moreProps;
|
|
162
|
+
const { className, displayInit = IndicatorDisplayTooltip.defaultProps.displayInit, onClick, onIconClick, width = 65, fontFamily, fontSize, fontWeight, textFill, labelFill, origin: originProp, displayFormat, displayValuesFor = IndicatorDisplayTooltip.defaultProps.displayValuesFor, options, } = this.props;
|
|
163
|
+
const currentItem = (_a = displayValuesFor(this.props, moreProps)) !== null && _a !== void 0 ? _a : last(fullData);
|
|
164
|
+
const config = chartConfig;
|
|
165
|
+
const origin = functor(originProp);
|
|
166
|
+
const [x, y] = origin(width, height);
|
|
167
|
+
const [ox, oy] = config.origin;
|
|
168
|
+
return (React.createElement("g", { transform: `translate(${ox + x}, ${oy + y})`, className: className }, options.map((each, idx) => {
|
|
169
|
+
let yValue;
|
|
170
|
+
const multiValues = [];
|
|
171
|
+
// Use single yAccessor if available
|
|
172
|
+
if (each.yAccessor && currentItem) {
|
|
173
|
+
yValue = each.yAccessor(currentItem);
|
|
174
|
+
}
|
|
175
|
+
// Calculate multiple yAccessor values if available
|
|
176
|
+
if (each.yAccessors && currentItem) {
|
|
177
|
+
multiValues.push(...each.yAccessors.map((accessor) => ({
|
|
178
|
+
label: accessor.label,
|
|
179
|
+
value: accessor.accessor(currentItem) ? displayFormat(accessor.accessor(currentItem)) : displayInit,
|
|
180
|
+
fill: accessor.fill,
|
|
181
|
+
showLabel: accessor.showLabel,
|
|
182
|
+
})));
|
|
183
|
+
}
|
|
184
|
+
const tooltipLabel = each.displayName || `${each.type} (${each.windowSize || "n/a"})`;
|
|
185
|
+
const yDisplayValue = yValue ? displayFormat(yValue) : displayInit;
|
|
186
|
+
return (React.createElement(SingleIndicatorDisplay, { key: idx, origin: [idx * 40, idx * 40], color: each.stroke, displayName: tooltipLabel, value: yDisplayValue, multiValues: multiValues, options: each, forChart: chartId, onClick: onClick, onIconClick: onIconClick, fontFamily: fontFamily, fontSize: fontSize, fontWeight: fontWeight, textFill: textFill, labelFill: labelFill }));
|
|
187
|
+
})));
|
|
188
|
+
};
|
|
189
|
+
}
|
|
190
|
+
render() {
|
|
191
|
+
return React.createElement(GenericChartComponent, { clip: false, svgDraw: this.renderSVG, drawOn: ["mousemove"] });
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
IndicatorDisplayTooltip.defaultProps = {
|
|
195
|
+
className: "react-financial-charts-tooltip react-financial-charts-indicator-display-tooltip",
|
|
196
|
+
displayFormat: format(".2f"),
|
|
197
|
+
displayInit: "n/a",
|
|
198
|
+
displayValuesFor: (_, props) => props.currentItem,
|
|
199
|
+
origin: [0, 10],
|
|
200
|
+
width: 65,
|
|
201
|
+
};
|
|
202
|
+
//# sourceMappingURL=IndicatorDisplayTooltip.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"IndicatorDisplayTooltip.js","sourceRoot":"","sources":["../src/IndicatorDisplayTooltip.tsx"],"names":[],"mappings":"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"}
|
package/lib/index.d.ts
CHANGED
package/lib/index.js
CHANGED
package/lib/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,wBAAwB,CAAC;AACvC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,eAAe,CAAC;AAC9B,cAAc,wBAAwB,CAAC;AACvC,cAAc,eAAe,CAAC;AAC9B,cAAc,cAAc,CAAC;AAC7B,cAAc,iBAAiB,CAAC;AAChC,cAAc,sBAAsB,CAAC;AACrC,cAAc,qBAAqB,CAAC;AACpC,cAAc,eAAe,CAAC;AAC9B,cAAc,qBAAqB,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,wBAAwB,CAAC;AACvC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,2BAA2B,CAAC;AAC1C,cAAc,eAAe,CAAC;AAC9B,cAAc,wBAAwB,CAAC;AACvC,cAAc,eAAe,CAAC;AAC9B,cAAc,cAAc,CAAC;AAC7B,cAAc,iBAAiB,CAAC;AAChC,cAAc,sBAAsB,CAAC;AACrC,cAAc,qBAAqB,CAAC;AACpC,cAAc,eAAe,CAAC;AAC9B,cAAc,qBAAqB,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tradingaction/tooltip",
|
|
3
|
-
"version": "2.1.
|
|
3
|
+
"version": "2.1.1",
|
|
4
4
|
"description": "Tooltips for react-financial-charts",
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"access": "public"
|
|
@@ -47,5 +47,5 @@
|
|
|
47
47
|
"react": "^16.0.0 || ^17.0.0 || ^18.0.0",
|
|
48
48
|
"react-dom": "^16.0.0 || ^17.0.0 || ^18.0.0"
|
|
49
49
|
},
|
|
50
|
-
"gitHead": "
|
|
50
|
+
"gitHead": "7b2ff867e360417cd983bc1423589ed5b826cca9"
|
|
51
51
|
}
|
|
@@ -0,0 +1,460 @@
|
|
|
1
|
+
import { functor, GenericChartComponent, last, MoreProps } from "@tradingaction/core";
|
|
2
|
+
import { format } from "d3-format";
|
|
3
|
+
import * as React from "react";
|
|
4
|
+
import { ToolTipText } from "./ToolTipText";
|
|
5
|
+
|
|
6
|
+
export interface IndicatorToolbarIcon {
|
|
7
|
+
readonly id: "eye" | "settings" | "code" | "delete" | "more";
|
|
8
|
+
readonly unicode: string;
|
|
9
|
+
readonly onClick: (option: IIndicatorDisplay) => void;
|
|
10
|
+
readonly size?: number;
|
|
11
|
+
readonly fillColor?: string;
|
|
12
|
+
readonly title?: string;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export interface MultiValueAccessor {
|
|
16
|
+
readonly label: string;
|
|
17
|
+
readonly accessor: (data: any) => number;
|
|
18
|
+
readonly fill?: string;
|
|
19
|
+
readonly showLabel?: boolean;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export interface IIndicatorDisplay {
|
|
23
|
+
readonly data?: any;
|
|
24
|
+
readonly yAccessor?: (data: any) => number;
|
|
25
|
+
readonly yAccessors?: MultiValueAccessor[];
|
|
26
|
+
readonly type: string;
|
|
27
|
+
readonly stroke: string;
|
|
28
|
+
readonly windowSize?: number;
|
|
29
|
+
readonly displayName?: string;
|
|
30
|
+
readonly icons?: IndicatorToolbarIcon[];
|
|
31
|
+
readonly orientation?: "vertical" | "horizontal";
|
|
32
|
+
readonly fillColor?: string;
|
|
33
|
+
readonly labelFill?: string;
|
|
34
|
+
readonly textFill?: string;
|
|
35
|
+
readonly fontFamily?: string;
|
|
36
|
+
readonly fontSize?: number;
|
|
37
|
+
readonly fontWeight?: number;
|
|
38
|
+
readonly showAccessorLabels?: boolean;
|
|
39
|
+
readonly alwaysShowFill?: boolean; // If true, always show background fill; otherwise only show on hover
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
interface SingleIndicatorDisplayProps {
|
|
43
|
+
readonly color: string;
|
|
44
|
+
readonly displayName: string;
|
|
45
|
+
readonly fontFamily?: string;
|
|
46
|
+
readonly fontSize?: number;
|
|
47
|
+
readonly fontWeight?: number;
|
|
48
|
+
readonly forChart: number | string;
|
|
49
|
+
readonly labelFill?: string;
|
|
50
|
+
readonly labelFontWeight?: number;
|
|
51
|
+
readonly textFill?: string;
|
|
52
|
+
readonly value: string;
|
|
53
|
+
readonly multiValues?: Array<{ label: string; value: string; fill?: string; showLabel?: boolean }>;
|
|
54
|
+
readonly options: IIndicatorDisplay;
|
|
55
|
+
readonly origin: [number, number];
|
|
56
|
+
readonly onClick?: (event: React.MouseEvent<SVGGElement, MouseEvent>, details: any) => void;
|
|
57
|
+
readonly onIconClick?: (event: React.MouseEvent<SVGTSpanElement, MouseEvent>, icon: IndicatorToolbarIcon) => void;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
interface SingleIndicatorDisplayState {
|
|
61
|
+
readonly isHovered: boolean;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
class SingleIndicatorDisplay extends React.Component<SingleIndicatorDisplayProps, SingleIndicatorDisplayState> {
|
|
65
|
+
private gRef = React.createRef<SVGGElement>();
|
|
66
|
+
|
|
67
|
+
constructor(props: SingleIndicatorDisplayProps) {
|
|
68
|
+
super(props);
|
|
69
|
+
this.state = {
|
|
70
|
+
isHovered: false,
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
private handleMouseEnter = () => {
|
|
75
|
+
this.setState({ isHovered: true });
|
|
76
|
+
};
|
|
77
|
+
|
|
78
|
+
private handleMouseLeave = () => {
|
|
79
|
+
this.setState({ isHovered: false });
|
|
80
|
+
};
|
|
81
|
+
|
|
82
|
+
private handleIconClick = (e: React.MouseEvent<SVGTSpanElement, MouseEvent>, icon: IndicatorToolbarIcon) => {
|
|
83
|
+
e.stopPropagation();
|
|
84
|
+
if (this.props.onIconClick) {
|
|
85
|
+
this.props.onIconClick(e, icon);
|
|
86
|
+
}
|
|
87
|
+
if (typeof icon.onClick === "function") {
|
|
88
|
+
icon.onClick(this.props.options);
|
|
89
|
+
}
|
|
90
|
+
};
|
|
91
|
+
|
|
92
|
+
public render() {
|
|
93
|
+
const {
|
|
94
|
+
color,
|
|
95
|
+
displayName,
|
|
96
|
+
fontSize,
|
|
97
|
+
fontFamily,
|
|
98
|
+
fontWeight,
|
|
99
|
+
textFill,
|
|
100
|
+
labelFill,
|
|
101
|
+
value,
|
|
102
|
+
multiValues,
|
|
103
|
+
origin,
|
|
104
|
+
options,
|
|
105
|
+
} = this.props;
|
|
106
|
+
const { isHovered } = this.state;
|
|
107
|
+
|
|
108
|
+
const translate = `translate(${origin[0]}, ${origin[1]})`;
|
|
109
|
+
const indicators = options.icons || [];
|
|
110
|
+
const orientation = options.orientation || "vertical";
|
|
111
|
+
|
|
112
|
+
// Use option-specific colors and fonts if provided, otherwise fall back to props
|
|
113
|
+
const effectiveLabelFill = options.labelFill || labelFill;
|
|
114
|
+
const effectiveTextFill = options.textFill || textFill;
|
|
115
|
+
const effectiveFontFamily = options.fontFamily || fontFamily;
|
|
116
|
+
const effectiveFontSize = options.fontSize ?? fontSize;
|
|
117
|
+
const effectiveFontWeight = options.fontWeight ?? fontWeight;
|
|
118
|
+
|
|
119
|
+
// Calculate dimensions based on orientation
|
|
120
|
+
let baseWidth = 200;
|
|
121
|
+
let baseHeight = 32;
|
|
122
|
+
let expandedWidth = isHovered ? 280 : 200;
|
|
123
|
+
let horizontalContentWidth = 0;
|
|
124
|
+
let displayNameWidth = 0;
|
|
125
|
+
|
|
126
|
+
if (multiValues && multiValues.length > 0) {
|
|
127
|
+
if (orientation === "vertical") {
|
|
128
|
+
// Vertical: height increases, width stays same
|
|
129
|
+
baseHeight = 32 + multiValues.length * 16;
|
|
130
|
+
expandedWidth = isHovered ? 280 : 200;
|
|
131
|
+
} else {
|
|
132
|
+
// Horizontal: calculate actual width based on visible labels and display name
|
|
133
|
+
const fontSize = effectiveFontSize || 12;
|
|
134
|
+
const charWidth = fontSize * 0.55; // Approximate character width for monospace/sans-serif
|
|
135
|
+
|
|
136
|
+
// Calculate display name width
|
|
137
|
+
displayNameWidth = displayName.length * charWidth + 10; // 10px after name
|
|
138
|
+
|
|
139
|
+
// Calculate values width
|
|
140
|
+
horizontalContentWidth = 0;
|
|
141
|
+
multiValues.forEach((multiValue, idx) => {
|
|
142
|
+
const showLabel = multiValue.showLabel !== undefined ? multiValue.showLabel : (options.showAccessorLabels === true);
|
|
143
|
+
|
|
144
|
+
if (showLabel) {
|
|
145
|
+
// Label width: "Label: "
|
|
146
|
+
const labelText = `${multiValue.label}: `;
|
|
147
|
+
horizontalContentWidth += labelText.length * charWidth;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
// Value width
|
|
151
|
+
const valueWidth = multiValue.value.length * charWidth;
|
|
152
|
+
horizontalContentWidth += valueWidth;
|
|
153
|
+
|
|
154
|
+
// Margin between values
|
|
155
|
+
if (idx < multiValues.length - 1) {
|
|
156
|
+
horizontalContentWidth += 8; // 8px margin between values
|
|
157
|
+
}
|
|
158
|
+
});
|
|
159
|
+
|
|
160
|
+
baseWidth = 20 + displayNameWidth + horizontalContentWidth; // 20px left padding + name + values
|
|
161
|
+
expandedWidth = isHovered ? baseWidth + 100 : baseWidth;
|
|
162
|
+
baseHeight = 25; // Reduced from 32 for tighter horizontal layout
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
return (
|
|
167
|
+
<g
|
|
168
|
+
ref={this.gRef}
|
|
169
|
+
transform={translate}
|
|
170
|
+
onClick={this.onClick}
|
|
171
|
+
onMouseEnter={this.handleMouseEnter}
|
|
172
|
+
onMouseLeave={this.handleMouseLeave}
|
|
173
|
+
style={{ cursor: "pointer" }}
|
|
174
|
+
>
|
|
175
|
+
{/* Indicator background */}
|
|
176
|
+
<rect
|
|
177
|
+
x={0}
|
|
178
|
+
y={0}
|
|
179
|
+
width={expandedWidth}
|
|
180
|
+
height={baseHeight}
|
|
181
|
+
fill={options.alwaysShowFill ? (options.fillColor || "#dbdfe4") : (isHovered ? (options.fillColor || "#dbdfe4") : "transparent")}
|
|
182
|
+
stroke={color}
|
|
183
|
+
strokeWidth={1}
|
|
184
|
+
rx={4}
|
|
185
|
+
style={{ transition: "width 0.2s ease" }}
|
|
186
|
+
/>
|
|
187
|
+
|
|
188
|
+
{/* Colored left border */}
|
|
189
|
+
<rect x={0} y={0} width={3} height={baseHeight} fill={color} rx={2} />
|
|
190
|
+
|
|
191
|
+
{/* Main indicator name and value - only show when no multiValues */}
|
|
192
|
+
{(!multiValues || multiValues.length === 0) && (
|
|
193
|
+
<ToolTipText x={10} y={18} fontFamily={effectiveFontFamily} fontSize={effectiveFontSize} fontWeight={effectiveFontWeight}>
|
|
194
|
+
<tspan fill={effectiveLabelFill} fontWeight={effectiveFontWeight} fontSize={effectiveFontSize || 12}>
|
|
195
|
+
{displayName}
|
|
196
|
+
</tspan>
|
|
197
|
+
<tspan x={10} dy={0} fill={effectiveTextFill} fontSize={effectiveFontSize || 12}>
|
|
198
|
+
|
|
199
|
+
</tspan>
|
|
200
|
+
<tspan fill={effectiveTextFill} fontSize={effectiveFontSize || 12}>
|
|
201
|
+
{value}
|
|
202
|
+
</tspan>
|
|
203
|
+
</ToolTipText>
|
|
204
|
+
)}
|
|
205
|
+
|
|
206
|
+
{/* Multiple value accessors */}
|
|
207
|
+
{multiValues && multiValues.length > 0 && (
|
|
208
|
+
<g>
|
|
209
|
+
{/* Display name for horizontal layout */}
|
|
210
|
+
{orientation === "horizontal" && (
|
|
211
|
+
<text
|
|
212
|
+
x={10}
|
|
213
|
+
y={17}
|
|
214
|
+
fontFamily={effectiveFontFamily}
|
|
215
|
+
fontSize={effectiveFontSize || 12}
|
|
216
|
+
fill={effectiveLabelFill}
|
|
217
|
+
fontWeight={effectiveFontWeight}
|
|
218
|
+
>
|
|
219
|
+
{displayName}
|
|
220
|
+
</text>
|
|
221
|
+
)}
|
|
222
|
+
|
|
223
|
+
{orientation === "vertical" ? (
|
|
224
|
+
// Vertical layout - display name + colon before values
|
|
225
|
+
<>
|
|
226
|
+
<text
|
|
227
|
+
x={10}
|
|
228
|
+
y={17}
|
|
229
|
+
fontFamily={effectiveFontFamily}
|
|
230
|
+
fontSize={effectiveFontSize || 12}
|
|
231
|
+
fill={effectiveLabelFill}
|
|
232
|
+
fontWeight={effectiveFontWeight}
|
|
233
|
+
>
|
|
234
|
+
{displayName}
|
|
235
|
+
</text>
|
|
236
|
+
{multiValues.map((multiValue, idx) => {
|
|
237
|
+
const showLabel = multiValue.showLabel !== undefined ? multiValue.showLabel : (options.showAccessorLabels === true);
|
|
238
|
+
return (
|
|
239
|
+
<text
|
|
240
|
+
key={`multi-${idx}`}
|
|
241
|
+
x={10}
|
|
242
|
+
y={17 + (idx + 1) * 16}
|
|
243
|
+
fontFamily={effectiveFontFamily}
|
|
244
|
+
fontSize={effectiveFontSize || 12}
|
|
245
|
+
fill={multiValue.fill || effectiveTextFill}
|
|
246
|
+
>
|
|
247
|
+
{showLabel && (
|
|
248
|
+
<tspan fontWeight={effectiveFontWeight} fill={effectiveLabelFill}>
|
|
249
|
+
{multiValue.label}:
|
|
250
|
+
</tspan>
|
|
251
|
+
)}
|
|
252
|
+
<tspan fill={multiValue.fill || effectiveTextFill}>{multiValue.value}</tspan>
|
|
253
|
+
</text>
|
|
254
|
+
);
|
|
255
|
+
})}
|
|
256
|
+
</>
|
|
257
|
+
) : (
|
|
258
|
+
// Horizontal layout - position based on actual content width
|
|
259
|
+
(() => {
|
|
260
|
+
const fontSize = effectiveFontSize || 12;
|
|
261
|
+
const charWidth = fontSize * 0.55;
|
|
262
|
+
const calcDisplayNameWidth = displayName.length * charWidth + 5;
|
|
263
|
+
let cumulativeX = 0 + calcDisplayNameWidth; // Start after display name
|
|
264
|
+
|
|
265
|
+
return multiValues.map((multiValue, idx) => {
|
|
266
|
+
const showLabel = multiValue.showLabel !== undefined ? multiValue.showLabel : (options.showAccessorLabels === true);
|
|
267
|
+
const x = cumulativeX;
|
|
268
|
+
|
|
269
|
+
// Calculate width for next position
|
|
270
|
+
if (showLabel) {
|
|
271
|
+
const labelText = `${multiValue.label}: `;
|
|
272
|
+
cumulativeX += labelText.length * charWidth;
|
|
273
|
+
}
|
|
274
|
+
cumulativeX += multiValue.value.length * charWidth;
|
|
275
|
+
|
|
276
|
+
// Add margin between values
|
|
277
|
+
if (idx < multiValues.length - 1) {
|
|
278
|
+
cumulativeX += 8;
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
return (
|
|
282
|
+
<text
|
|
283
|
+
key={`multi-${idx}`}
|
|
284
|
+
x={x}
|
|
285
|
+
y={17}
|
|
286
|
+
fontFamily={effectiveFontFamily}
|
|
287
|
+
fontSize={effectiveFontSize || 12}
|
|
288
|
+
fill={multiValue.fill || effectiveTextFill}
|
|
289
|
+
>
|
|
290
|
+
{showLabel && (
|
|
291
|
+
<tspan fontWeight={effectiveFontWeight} fill={effectiveLabelFill} fontSize={(effectiveFontSize || 12) - 1}>
|
|
292
|
+
{multiValue.label}:
|
|
293
|
+
</tspan>
|
|
294
|
+
)}
|
|
295
|
+
<tspan fill={multiValue.fill || effectiveTextFill}>{multiValue.value}</tspan>
|
|
296
|
+
</text>
|
|
297
|
+
);
|
|
298
|
+
});
|
|
299
|
+
})()
|
|
300
|
+
)}
|
|
301
|
+
</g>
|
|
302
|
+
)}
|
|
303
|
+
|
|
304
|
+
{/* Toolbar icons on hover */}
|
|
305
|
+
{isHovered && indicators.length > 0 && (
|
|
306
|
+
<g>
|
|
307
|
+
{indicators.map((icon, idx) => {
|
|
308
|
+
let iconX: number;
|
|
309
|
+
if (orientation === "horizontal" && multiValues && multiValues.length > 0) {
|
|
310
|
+
// Position after calculated content width with spacing
|
|
311
|
+
iconX = 20 + displayNameWidth + horizontalContentWidth + 10 + idx * 16;
|
|
312
|
+
} else {
|
|
313
|
+
// Position for vertical or single value
|
|
314
|
+
iconX = 210 + idx * 16;
|
|
315
|
+
}
|
|
316
|
+
return (
|
|
317
|
+
<g key={icon.id} onClick={(e: any) => this.handleIconClick(e, icon)}>
|
|
318
|
+
{icon.title && <title>{icon.title}</title>}
|
|
319
|
+
<text
|
|
320
|
+
x={iconX}
|
|
321
|
+
y={17}
|
|
322
|
+
fontSize={icon.size || 14}
|
|
323
|
+
fill={icon.fillColor || "#9ca3af"}
|
|
324
|
+
style={{
|
|
325
|
+
cursor: "pointer",
|
|
326
|
+
userSelect: "none",
|
|
327
|
+
transition: "fill 0.2s ease",
|
|
328
|
+
pointerEvents: "auto",
|
|
329
|
+
}}
|
|
330
|
+
onMouseEnter={(e: any) => (e.target.style.fill = "#fff")}
|
|
331
|
+
onMouseLeave={(e: any) => (e.target.style.fill = icon.fillColor || "#9ca3af")}
|
|
332
|
+
>
|
|
333
|
+
{icon.unicode}
|
|
334
|
+
</text>
|
|
335
|
+
</g>
|
|
336
|
+
);
|
|
337
|
+
})}
|
|
338
|
+
</g>
|
|
339
|
+
)}
|
|
340
|
+
</g>
|
|
341
|
+
);
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
private readonly onClick = (event: React.MouseEvent<SVGGElement, MouseEvent>) => {
|
|
345
|
+
const { onClick, forChart, options } = this.props;
|
|
346
|
+
if (onClick !== undefined) {
|
|
347
|
+
onClick(event, { chartId: forChart, ...options });
|
|
348
|
+
}
|
|
349
|
+
};
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
export interface IndicatorDisplayTooltipProps {
|
|
353
|
+
readonly className?: string;
|
|
354
|
+
readonly displayFormat: (value: number) => string;
|
|
355
|
+
readonly origin: number[];
|
|
356
|
+
readonly displayInit?: string;
|
|
357
|
+
readonly displayValuesFor?: (props: IndicatorDisplayTooltipProps, moreProps: any) => any;
|
|
358
|
+
readonly onClick?: (event: React.MouseEvent<SVGGElement, MouseEvent>) => void;
|
|
359
|
+
readonly onIconClick?: (event: React.MouseEvent<SVGTSpanElement, MouseEvent>, icon: IndicatorToolbarIcon) => void;
|
|
360
|
+
readonly textFill?: string;
|
|
361
|
+
readonly labelFill?: string;
|
|
362
|
+
readonly fontFamily?: string;
|
|
363
|
+
readonly fontSize?: number;
|
|
364
|
+
readonly fontWeight?: number;
|
|
365
|
+
readonly width?: number;
|
|
366
|
+
readonly options: IIndicatorDisplay[];
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
// tslint:disable-next-line: max-classes-per-file
|
|
370
|
+
export class IndicatorDisplayTooltip extends React.Component<IndicatorDisplayTooltipProps> {
|
|
371
|
+
public static defaultProps = {
|
|
372
|
+
className: "react-financial-charts-tooltip react-financial-charts-indicator-display-tooltip",
|
|
373
|
+
displayFormat: format(".2f"),
|
|
374
|
+
displayInit: "n/a",
|
|
375
|
+
displayValuesFor: (_: any, props: any) => props.currentItem,
|
|
376
|
+
origin: [0, 10],
|
|
377
|
+
width: 65,
|
|
378
|
+
};
|
|
379
|
+
|
|
380
|
+
public render() {
|
|
381
|
+
return <GenericChartComponent clip={false} svgDraw={this.renderSVG} drawOn={["mousemove"]} />;
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
private readonly renderSVG = (moreProps: MoreProps) => {
|
|
385
|
+
const { chartId, chartConfig, chartConfig: { height = 0 } = {}, fullData } = moreProps;
|
|
386
|
+
|
|
387
|
+
const {
|
|
388
|
+
className,
|
|
389
|
+
displayInit = IndicatorDisplayTooltip.defaultProps.displayInit,
|
|
390
|
+
onClick,
|
|
391
|
+
onIconClick,
|
|
392
|
+
width = 65,
|
|
393
|
+
fontFamily,
|
|
394
|
+
fontSize,
|
|
395
|
+
fontWeight,
|
|
396
|
+
textFill,
|
|
397
|
+
labelFill,
|
|
398
|
+
origin: originProp,
|
|
399
|
+
displayFormat,
|
|
400
|
+
displayValuesFor = IndicatorDisplayTooltip.defaultProps.displayValuesFor,
|
|
401
|
+
options,
|
|
402
|
+
} = this.props;
|
|
403
|
+
|
|
404
|
+
const currentItem = displayValuesFor(this.props, moreProps) ?? last(fullData);
|
|
405
|
+
const config = chartConfig!;
|
|
406
|
+
|
|
407
|
+
const origin = functor(originProp);
|
|
408
|
+
const [x, y] = origin(width, height);
|
|
409
|
+
const [ox, oy] = config.origin;
|
|
410
|
+
|
|
411
|
+
return (
|
|
412
|
+
<g transform={`translate(${ox + x}, ${oy + y})`} className={className}>
|
|
413
|
+
{options.map((each, idx) => {
|
|
414
|
+
let yValue: number | undefined;
|
|
415
|
+
const multiValues: Array<{ label: string; value: string; fill?: string }> = [];
|
|
416
|
+
|
|
417
|
+
// Use single yAccessor if available
|
|
418
|
+
if (each.yAccessor && currentItem) {
|
|
419
|
+
yValue = each.yAccessor(currentItem);
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
// Calculate multiple yAccessor values if available
|
|
423
|
+
if (each.yAccessors && currentItem) {
|
|
424
|
+
multiValues.push(
|
|
425
|
+
...each.yAccessors.map((accessor) => ({
|
|
426
|
+
label: accessor.label,
|
|
427
|
+
value: accessor.accessor(currentItem) ? displayFormat(accessor.accessor(currentItem)) : displayInit,
|
|
428
|
+
fill: accessor.fill,
|
|
429
|
+
showLabel: accessor.showLabel,
|
|
430
|
+
})),
|
|
431
|
+
);
|
|
432
|
+
}
|
|
433
|
+
|
|
434
|
+
const tooltipLabel = each.displayName || `${each.type} (${each.windowSize || "n/a"})`;
|
|
435
|
+
const yDisplayValue = yValue ? displayFormat(yValue) : displayInit;
|
|
436
|
+
|
|
437
|
+
return (
|
|
438
|
+
<SingleIndicatorDisplay
|
|
439
|
+
key={idx}
|
|
440
|
+
origin={[idx * 40, idx * 40]}
|
|
441
|
+
color={each.stroke}
|
|
442
|
+
displayName={tooltipLabel}
|
|
443
|
+
value={yDisplayValue}
|
|
444
|
+
multiValues={multiValues}
|
|
445
|
+
options={each}
|
|
446
|
+
forChart={chartId}
|
|
447
|
+
onClick={onClick}
|
|
448
|
+
onIconClick={onIconClick}
|
|
449
|
+
fontFamily={fontFamily}
|
|
450
|
+
fontSize={fontSize}
|
|
451
|
+
fontWeight={fontWeight}
|
|
452
|
+
textFill={textFill}
|
|
453
|
+
labelFill={labelFill}
|
|
454
|
+
/>
|
|
455
|
+
);
|
|
456
|
+
})}
|
|
457
|
+
</g>
|
|
458
|
+
);
|
|
459
|
+
};
|
|
460
|
+
}
|
package/src/index.ts
CHANGED