feat: improve chart tooltips

This commit is contained in:
Vyacheslav Matyukhin 2022-05-05 01:38:31 +04:00
parent e155781fcb
commit b723c3026b
No known key found for this signature in database
GPG Key ID: 3D2A774C5489F96C

View File

@ -13,11 +13,11 @@ interface Props {
question: QuestionWithHistoryFragment; question: QuestionWithHistoryFragment;
} }
let formatOptionName = (name: string) => { const formatOptionName = (name: string) => {
return name.length > 20 ? name.slice(0, 17) + "..." : name; return name.length > 20 ? name.slice(0, 17) + "..." : name;
}; };
let getLength = (str: string): number => { const getLength = (str: string): number => {
// TODO - measure with temporary DOM element instead? // TODO - measure with temporary DOM element instead?
const capitalLetterLengthMultiplier = 1.25; const capitalLetterLengthMultiplier = 1.25;
const smallLetterMultiplier = 0.8; const smallLetterMultiplier = 0.8;
@ -33,21 +33,14 @@ let getLength = (str: string): number => {
return length; return length;
}; };
type DataSet = { date: Date; probability: number; name: string }[]; type DataSet = { x: Date; y: number; name: string }[];
const dataAsXy = (data: DataSet) =>
data.map((datum) => ({
x: datum.date,
y: datum.probability,
name: datum.name,
}));
const colors = ["dodgerblue", "crimson", "seagreen", "darkviolet", "turquoise"]; const colors = ["dodgerblue", "crimson", "seagreen", "darkviolet", "turquoise"];
// can't be replaced with React component, VictoryChart requires VictoryGroup elements to be immediate children // can't be replaced with React component, VictoryChart requires VictoryGroup elements to be immediate children
const getVictoryGroup = ({ data, i }: { data: DataSet; i: number }) => { const getVictoryGroup = ({ data, i }: { data: DataSet; i: number }) => {
return ( return (
<VictoryGroup color={colors[i] || "darkgray"} data={dataAsXy(data)} key={i}> <VictoryGroup color={colors[i] || "darkgray"} data={data} key={i}>
<VictoryScatter <VictoryScatter
name={`scatter-${i}`} name={`scatter-${i}`}
size={({ active }) => (active ? 3.75 : 3)} size={({ active }) => (active ? 3.75 : 3)}
@ -86,13 +79,13 @@ export const HistoryChart: React.FC<Props> = ({ question }) => {
const relevantItemsArray = item.options.filter((x) => x.name === name); const relevantItemsArray = item.options.filter((x) => x.name === name);
const date = new Date(item.timestamp * 1000); const date = new Date(item.timestamp * 1000);
if ( if (
relevantItemsArray.length == 1 && relevantItemsArray.length === 1 &&
item.timestamp - previousDate > 12 * 60 * 60 item.timestamp - previousDate > 12 * 60 * 60
) { ) {
let relevantItem = relevantItemsArray[0]; let relevantItem = relevantItemsArray[0];
let result = { const result = {
date, x: date,
probability: relevantItem.probability, y: relevantItem.probability,
name: relevantItem.name, name: relevantItem.name,
}; };
maxProbability = maxProbability =
@ -157,22 +150,43 @@ export const HistoryChart: React.FC<Props> = ({ question }) => {
constrainToVisibleArea constrainToVisibleArea
pointerLength={0} pointerLength={0}
dy={-12} dy={-12}
text={({ datum }) => labelComponent={
`${datum.name}: ${Math.round(datum.y * 100)}%` <VictoryLabel
} style={[
style={{ {
fontSize: 15, fontSize: 16,
fill: "black", fill: "black",
strokeWidth: 0.05, strokeWidth: 0.05,
}} },
flyoutStyle={{ {
stroke: "black", fontSize: 16,
fill: "white", fill: "#777",
}} strokeWidth: 0.05,
cornerRadius={0} },
flyoutPadding={7} ]}
/> />
} }
text={({ datum }) =>
`${datum.name}: ${Math.round(datum.y * 100)}%\n${format(
datum.x,
"yyyy-MM-dd"
)}`
}
style={{
fontSize: 16, // needs to be set here and not just in labelComponent for text size calculations
fontFamily:
'"Gill Sans", "Gill Sans MT", "Ser­avek", "Trebuchet MS", sans-serif',
// default font family from Victory, need to be specified explicitly for some reason, otherwise text size gets miscalculated
}}
flyoutStyle={{
stroke: "#999",
fill: "white",
}}
cornerRadius={4}
flyoutPadding={{ top: 4, bottom: 4, left: 12, right: 12 }}
/>
}
radius={50}
voronoiBlacklist={ voronoiBlacklist={
[...Array(5).keys()].map((i) => `line-${i}`) [...Array(5).keys()].map((i) => `line-${i}`)
// see: https://github.com/FormidableLabs/victory/issues/545 // see: https://github.com/FormidableLabs/victory/issues/545
@ -209,7 +223,7 @@ export const HistoryChart: React.FC<Props> = ({ question }) => {
<VictoryLabel <VictoryLabel
dy={10} dy={10}
angle={-30} angle={-30}
style={{ fontSize: 15, fill: "gray" }} style={{ fontSize: 15, fill: "#777" }}
/> />
} }
scale={{ x: "time" }} scale={{ x: "time" }}
@ -221,7 +235,7 @@ export const HistoryChart: React.FC<Props> = ({ question }) => {
grid: { stroke: "#D3D3D3", strokeWidth: 0.5 }, grid: { stroke: "#D3D3D3", strokeWidth: 0.5 },
}} }}
tickLabelComponent={ tickLabelComponent={
<VictoryLabel dy={0} style={{ fontSize: 15, fill: "gray" }} /> <VictoryLabel dy={0} style={{ fontSize: 15, fill: "#777" }} />
} }
// tickFormat specifies how ticks should be displayed // tickFormat specifies how ticks should be displayed
tickFormat={(x) => `${x * 100}%`} tickFormat={(x) => `${x * 100}%`}