Skip to content

Commit

Permalink
feat(tooltip): adding change to ohlc tooltip
Browse files Browse the repository at this point in the history
Removed volume since it's not related to ohlc.
  • Loading branch information
markmcdowell committed Jul 23, 2020
1 parent dfb0839 commit bc38b73
Show file tree
Hide file tree
Showing 2 changed files with 80 additions and 112 deletions.
2 changes: 1 addition & 1 deletion packages/stories/src/features/tooltips/Tooltips.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ class Tooltips extends React.Component<ChartProps> {
<CandlestickSeries />
<LineSeries yAccessor={ema12.accessor()} strokeStyle={ema12.stroke()} />

<OHLCTooltip origin={[8, 16]} />
<OHLCTooltip origin={[8, 16]} textFill={(d) => (d.close > d.open ? "#26a69a" : "#ef5350")} />
<HoverTooltip
yAccessor={ema12.accessor()}
tooltip={{
Expand Down
190 changes: 79 additions & 111 deletions packages/tooltip/src/OHLCTooltip.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import { functor, isDefined, GenericChartComponent, last } from "@react-financial-charts/core";
import { functor, GenericChartComponent, last } from "@react-financial-charts/core";
import { format } from "d3-format";
import { timeFormat } from "d3-time-format";
import * as React from "react";
import { ToolTipText } from "./ToolTipText";
import { ToolTipTSpanLabel } from "./ToolTipTSpanLabel";
Expand All @@ -10,95 +9,42 @@ const displayTextsDefault = {
h: " H: ",
l: " L: ",
c: " C: ",
v: " Vol: ",
na: "n/a",
};

const defaultDisplay = (props: OHLCTooltipProps, _, itemsToDisplay) => {
const { className, textFill, labelFill, onClick, fontFamily, fontSize, displayTexts } = props;

const { open, high, low, close, volume, x, y } = itemsToDisplay;

return (
<g
className={`react-financial-charts-tooltip-hover ${className}`}
transform={`translate(${x}, ${y})`}
onClick={onClick}
>
<ToolTipText x={0} y={0} fontFamily={fontFamily} fontSize={fontSize}>
<ToolTipTSpanLabel fill={labelFill} key="label_O">
{displayTexts.o}
</ToolTipTSpanLabel>
<tspan key="value_O" fill={textFill}>
{open}
</tspan>
<ToolTipTSpanLabel fill={labelFill} key="label_H">
{displayTexts.h}
</ToolTipTSpanLabel>
<tspan key="value_H" fill={textFill}>
{high}
</tspan>
<ToolTipTSpanLabel fill={labelFill} key="label_L">
{displayTexts.l}
</ToolTipTSpanLabel>
<tspan key="value_L" fill={textFill}>
{low}
</tspan>
<ToolTipTSpanLabel fill={labelFill} key="label_C">
{displayTexts.c}
</ToolTipTSpanLabel>
<tspan key="value_C" fill={textFill}>
{close}
</tspan>
<ToolTipTSpanLabel fill={labelFill} key="label_Vol">
{displayTexts.v}
</ToolTipTSpanLabel>
<tspan key="value_Vol" fill={textFill}>
{volume}
</tspan>
</ToolTipText>
</g>
);
};

interface OHLCTooltipProps {
readonly accessor?: any; // func
readonly accessor?: (data: any) => any;
readonly className?: string;
readonly children?: any; // func
readonly displayTexts?: any;
readonly displayValuesFor?: any; // func
readonly changeFormat?: (n: number | { valueOf(): number }) => string;
readonly displayTexts?: {
o: string;
h: string;
l: string;
c: string;
na: string;
};
readonly displayValuesFor?: (props: OHLCTooltipProps, moreProps: any) => any;
readonly fontFamily?: string;
readonly fontSize?: number;
readonly labelFill?: string;
readonly ohlcFormat?: (n: number | { valueOf(): number }) => string;
readonly onClick?: (event: React.MouseEvent<SVGGElement, MouseEvent>) => void;
readonly origin?: [number, number] | ((width: number, height: number) => [number, number]);
readonly percentFormat?: (n: number | { valueOf(): number }) => string;
readonly textFill?: string;
readonly volumeFormat?: (n: number | { valueOf(): number }) => string;
readonly xDisplayFormat?: (date: Date) => string;
readonly textFill?: string | ((item: any) => string);
}

export class OHLCTooltip extends React.Component<OHLCTooltipProps> {
public static defaultProps = {
accessor: (d) => {
return {
date: d.date,
open: d.open,
high: d.high,
low: d.low,
close: d.close,
volume: d.volume,
};
},
xDisplayFormat: timeFormat("%Y-%m-%d"),
volumeFormat: format(".4s"),
percentFormat: format(".2%"),
ohlcFormat: format(".2f"),
accessor: (d: unknown) => d,
changeFormat: format("+.2f"),
className: "react-financial-charts-tooltip-hover",
displayTexts: displayTextsDefault,
displayValuesFor: (_, props) => props.currentItem,
fontFamily: "-apple-system, system-ui, 'Helvetica Neue', Ubuntu, sans-serif",
ohlcFormat: format(".2f"),
origin: [0, 0],
children: defaultDisplay,
displayTexts: displayTextsDefault,
percentFormat: format("+.2%"),
};

public render() {
Expand All @@ -107,60 +53,82 @@ export class OHLCTooltip extends React.Component<OHLCTooltipProps> {

private readonly renderSVG = (moreProps) => {
const {
displayValuesFor,
xDisplayFormat = OHLCTooltip.defaultProps.xDisplayFormat,
accessor,
volumeFormat = OHLCTooltip.defaultProps.volumeFormat,
changeFormat = OHLCTooltip.defaultProps.changeFormat,
className,
displayTexts = OHLCTooltip.defaultProps.displayTexts,
displayValuesFor = OHLCTooltip.defaultProps.displayValuesFor,
fontFamily,
fontSize,
labelFill,
ohlcFormat = OHLCTooltip.defaultProps.ohlcFormat,
onClick,
percentFormat = OHLCTooltip.defaultProps.percentFormat,
displayTexts,
textFill,
} = this.props;

const {
chartConfig: { width, height },
displayXAccessor,
fullData,
} = moreProps;

const currentItem = displayValuesFor(this.props, moreProps) ?? last(fullData);

let displayDate;
let open;
let high;
let low;
let close;
let volume;
let percent;
let open: string = displayTexts.na;
let high: string = displayTexts.na;
let low: string = displayTexts.na;
let close: string = displayTexts.na;
let change: string = displayTexts.na;

displayDate = open = high = low = close = volume = percent = displayTexts.na;

if (isDefined(currentItem) && isDefined(accessor(currentItem))) {
if (currentItem !== undefined && accessor !== undefined) {
const item = accessor(currentItem);
volume = isDefined(item.volume) ? volumeFormat(item.volume) : displayTexts.na;

displayDate = xDisplayFormat(displayXAccessor(item));
open = ohlcFormat(item.open);
high = ohlcFormat(item.high);
low = ohlcFormat(item.low);
close = ohlcFormat(item.close);
percent = percentFormat((item.close - item.open) / item.open);
if (item !== undefined) {
open = ohlcFormat(item.open);
high = ohlcFormat(item.high);
low = ohlcFormat(item.low);
close = ohlcFormat(item.close);
change = `${changeFormat(item.close - item.open)} (${percentFormat(
(item.close - item.open) / item.open,
)})`;
}
}

const { origin: originProp } = this.props;
const origin = functor(originProp);
const [x, y] = origin(width, height);

const itemsToDisplay = {
displayDate,
open,
high,
low,
close,
percent,
volume,
x,
y,
};
return this.props.children(this.props, moreProps, itemsToDisplay);
const [x, y] = functor(originProp)(width, height);
const valueFill = functor(textFill)(currentItem);

return (
<g className={className} transform={`translate(${x}, ${y})`} onClick={onClick}>
<ToolTipText x={0} y={0} fontFamily={fontFamily} fontSize={fontSize}>
<ToolTipTSpanLabel fill={labelFill} key="label_O">
{displayTexts.o}
</ToolTipTSpanLabel>
<tspan key="value_O" fill={valueFill}>
{open}
</tspan>
<ToolTipTSpanLabel fill={labelFill} key="label_H">
{displayTexts.h}
</ToolTipTSpanLabel>
<tspan key="value_H" fill={valueFill}>
{high}
</tspan>
<ToolTipTSpanLabel fill={labelFill} key="label_L">
{displayTexts.l}
</ToolTipTSpanLabel>
<tspan key="value_L" fill={valueFill}>
{low}
</tspan>
<ToolTipTSpanLabel fill={labelFill} key="label_C">
{displayTexts.c}
</ToolTipTSpanLabel>
<tspan key="value_C" fill={valueFill}>
{close}
</tspan>
<tspan key="value_Change" fill={valueFill}>
{` ${change}`}
</tspan>
</ToolTipText>
</g>
);
};
}

0 comments on commit bc38b73

Please sign in to comment.