feat: full legend items name on hover
This commit is contained in:
parent
066b79fe12
commit
a2f94efcc7
68
package-lock.json
generated
68
package-lock.json
generated
|
@ -9,6 +9,7 @@
|
|||
"version": "2.0.0",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@floating-ui/react-dom": "^0.7.0",
|
||||
"@graphql-yoga/node": "^2.1.0",
|
||||
"@pothos/core": "^3.5.1",
|
||||
"@pothos/plugin-prisma": "^3.4.0",
|
||||
|
@ -1468,6 +1469,32 @@
|
|||
"graphql": "^14.0.0 || ^15.0.0 || ^16.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@floating-ui/core": {
|
||||
"version": "0.7.0",
|
||||
"resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-0.7.0.tgz",
|
||||
"integrity": "sha512-W7+i5Suhhvv97WDTW//KqUA43f/2a4abprM1rWqtLM9lIlJ29tbFI8h232SvqunXon0WmKNEKVjbOsgBhTnbLw=="
|
||||
},
|
||||
"node_modules/@floating-ui/dom": {
|
||||
"version": "0.5.0",
|
||||
"resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-0.5.0.tgz",
|
||||
"integrity": "sha512-PS75dnMg4GdWjDFOiOs15cDzYJpukRNHqQn0ugrBlsrpk2n+y8bwZ24XrsdLSL7kxshmxxr2nTNycLnmRIvV7g==",
|
||||
"dependencies": {
|
||||
"@floating-ui/core": "^0.7.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@floating-ui/react-dom": {
|
||||
"version": "0.7.0",
|
||||
"resolved": "https://registry.npmjs.org/@floating-ui/react-dom/-/react-dom-0.7.0.tgz",
|
||||
"integrity": "sha512-mpYGykTqwtBYT+ZTQQ2OfZ6wXJNuUgmqqD9ooCgbMRgvul6InFOTtWYvtujps439hmOFiVPm4PoBkEEn5imidg==",
|
||||
"dependencies": {
|
||||
"@floating-ui/dom": "^0.5.0",
|
||||
"use-isomorphic-layout-effect": "^1.1.1"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": ">=16.8.0",
|
||||
"react-dom": ">=16.8.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@glennsl/bs-json": {
|
||||
"version": "5.0.4",
|
||||
"resolved": "https://registry.npmjs.org/@glennsl%2fbs-json/-/bs-json-5.0.4.tgz",
|
||||
|
@ -39293,6 +39320,19 @@
|
|||
"node": ">= 10.x"
|
||||
}
|
||||
},
|
||||
"node_modules/use-isomorphic-layout-effect": {
|
||||
"version": "1.1.2",
|
||||
"resolved": "https://registry.npmjs.org/use-isomorphic-layout-effect/-/use-isomorphic-layout-effect-1.1.2.tgz",
|
||||
"integrity": "sha512-49L8yCO3iGT/ZF9QttjwLF/ZD9Iwto5LnH5LmEdk/6cFmXddqi2ulF0edxTwjj+7mqvpVVGQWvbXZdn32wRSHA==",
|
||||
"peerDependencies": {
|
||||
"react": "^16.8.0 || ^17.0.0 || ^18.0.0"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"@types/react": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/use-subscription": {
|
||||
"version": "1.5.1",
|
||||
"resolved": "https://registry.npmjs.org/use-subscription/-/use-subscription-1.5.1.tgz",
|
||||
|
@ -41182,6 +41222,28 @@
|
|||
"tiny-lru": "7.0.6"
|
||||
}
|
||||
},
|
||||
"@floating-ui/core": {
|
||||
"version": "0.7.0",
|
||||
"resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-0.7.0.tgz",
|
||||
"integrity": "sha512-W7+i5Suhhvv97WDTW//KqUA43f/2a4abprM1rWqtLM9lIlJ29tbFI8h232SvqunXon0WmKNEKVjbOsgBhTnbLw=="
|
||||
},
|
||||
"@floating-ui/dom": {
|
||||
"version": "0.5.0",
|
||||
"resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-0.5.0.tgz",
|
||||
"integrity": "sha512-PS75dnMg4GdWjDFOiOs15cDzYJpukRNHqQn0ugrBlsrpk2n+y8bwZ24XrsdLSL7kxshmxxr2nTNycLnmRIvV7g==",
|
||||
"requires": {
|
||||
"@floating-ui/core": "^0.7.0"
|
||||
}
|
||||
},
|
||||
"@floating-ui/react-dom": {
|
||||
"version": "0.7.0",
|
||||
"resolved": "https://registry.npmjs.org/@floating-ui/react-dom/-/react-dom-0.7.0.tgz",
|
||||
"integrity": "sha512-mpYGykTqwtBYT+ZTQQ2OfZ6wXJNuUgmqqD9ooCgbMRgvul6InFOTtWYvtujps439hmOFiVPm4PoBkEEn5imidg==",
|
||||
"requires": {
|
||||
"@floating-ui/dom": "^0.5.0",
|
||||
"use-isomorphic-layout-effect": "^1.1.1"
|
||||
}
|
||||
},
|
||||
"@glennsl/bs-json": {
|
||||
"version": "5.0.4",
|
||||
"resolved": "https://registry.npmjs.org/@glennsl%2fbs-json/-/bs-json-5.0.4.tgz",
|
||||
|
@ -69331,6 +69393,12 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"use-isomorphic-layout-effect": {
|
||||
"version": "1.1.2",
|
||||
"resolved": "https://registry.npmjs.org/use-isomorphic-layout-effect/-/use-isomorphic-layout-effect-1.1.2.tgz",
|
||||
"integrity": "sha512-49L8yCO3iGT/ZF9QttjwLF/ZD9Iwto5LnH5LmEdk/6cFmXddqi2ulF0edxTwjj+7mqvpVVGQWvbXZdn32wRSHA==",
|
||||
"requires": {}
|
||||
},
|
||||
"use-subscription": {
|
||||
"version": "1.5.1",
|
||||
"resolved": "https://registry.npmjs.org/use-subscription/-/use-subscription-1.5.1.tgz",
|
||||
|
|
|
@ -27,6 +27,7 @@
|
|||
"dbshell": ". .env && psql $DIGITALOCEAN_POSTGRES"
|
||||
},
|
||||
"dependencies": {
|
||||
"@floating-ui/react-dom": "^0.7.0",
|
||||
"@graphql-yoga/node": "^2.1.0",
|
||||
"@pothos/core": "^3.5.1",
|
||||
"@pothos/plugin-prisma": "^3.4.0",
|
||||
|
|
|
@ -16,7 +16,6 @@ const getVictoryGroup = ({
|
|||
i: number;
|
||||
highlight?: boolean;
|
||||
}) => {
|
||||
console.log(i, data, highlight, data.length);
|
||||
return (
|
||||
<VictoryGroup color={chartColors[i] || "darkgray"} data={data} key={i}>
|
||||
<VictoryLine
|
||||
|
|
85
src/web/questions/components/HistoryChart/Legend.tsx
Normal file
85
src/web/questions/components/HistoryChart/Legend.tsx
Normal file
|
@ -0,0 +1,85 @@
|
|||
import { useRef, useState } from "react";
|
||||
|
||||
import { shift, useFloating } from "@floating-ui/react-dom";
|
||||
|
||||
type Item = {
|
||||
name: string;
|
||||
color: string;
|
||||
};
|
||||
|
||||
const LegendItem: React.FC<{ item: Item; onHighlight: () => void }> = ({
|
||||
item,
|
||||
onHighlight,
|
||||
}) => {
|
||||
const { x, y, reference, floating, strategy } = useFloating({
|
||||
// placement: "right",
|
||||
middleware: [shift()],
|
||||
});
|
||||
|
||||
const [showTooltip, setShowTooltip] = useState(false);
|
||||
const textRef = useRef<HTMLDivElement>();
|
||||
|
||||
const onHover = () => {
|
||||
if (textRef.current.scrollWidth > textRef.current.clientWidth) {
|
||||
setShowTooltip(true);
|
||||
}
|
||||
onHighlight();
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<div
|
||||
className="flex items-center cursor-pointer"
|
||||
onMouseOver={onHover}
|
||||
onMouseLeave={() => setShowTooltip(false)}
|
||||
ref={reference}
|
||||
>
|
||||
<svg className="mt-1 shrink-0" height="10" width="16">
|
||||
<circle cx="4" cy="4" r="4" fill={item.color} />
|
||||
</svg>
|
||||
<div
|
||||
className="text-xs sm:text-sm sm:whitespace-nowrap sm:text-ellipsis sm:overflow-hidden sm:max-w-160"
|
||||
ref={textRef}
|
||||
>
|
||||
{item.name}
|
||||
</div>
|
||||
</div>
|
||||
{showTooltip
|
||||
? (() => {
|
||||
return (
|
||||
<div
|
||||
className={`absolute text-xs p-2 border border-gray-300 rounded bg-white ${
|
||||
showTooltip ? "" : "hidden"
|
||||
}`}
|
||||
ref={floating}
|
||||
style={{
|
||||
position: strategy,
|
||||
top: y ?? "",
|
||||
left: x ?? "",
|
||||
}}
|
||||
>
|
||||
{item.name}
|
||||
</div>
|
||||
);
|
||||
})()
|
||||
: null}
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export const Legend: React.FC<{
|
||||
items: { name: string; color: string }[];
|
||||
setHighlight: (i: number | undefined) => void;
|
||||
}> = ({ items, setHighlight }) => {
|
||||
return (
|
||||
<div className="space-y-2" onMouseLeave={() => setHighlight(undefined)}>
|
||||
{items.map((item, i) => (
|
||||
<LegendItem
|
||||
key={item.name}
|
||||
item={item}
|
||||
onHighlight={() => setHighlight(i)}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
};
|
|
@ -3,6 +3,7 @@ import React, { useMemo, useState } from "react";
|
|||
|
||||
import { QuestionWithHistoryFragment } from "../../../fragments.generated";
|
||||
import { InnerChartPlaceholder } from "./InnerChartPlaceholder";
|
||||
import { Legend } from "./Legend";
|
||||
import { buildChartData, chartColors } from "./utils";
|
||||
|
||||
const InnerChart = dynamic(
|
||||
|
@ -14,30 +15,6 @@ interface Props {
|
|||
question: QuestionWithHistoryFragment;
|
||||
}
|
||||
|
||||
const Legend: React.FC<{
|
||||
items: { name: string; color: string }[];
|
||||
setHighlight: (i: number | undefined) => void;
|
||||
}> = ({ items, setHighlight }) => {
|
||||
return (
|
||||
<div className="space-y-2" onMouseLeave={() => setHighlight(undefined)}>
|
||||
{items.map((item, i) => (
|
||||
<div
|
||||
className="flex items-center"
|
||||
key={item.name}
|
||||
onMouseOver={() => setHighlight(i)}
|
||||
>
|
||||
<svg className="mt-1 shrink-0" height="10" width="16">
|
||||
<circle cx="4" cy="4" r="4" fill={item.color} />
|
||||
</svg>
|
||||
<span className="text-xs sm:text-sm sm:whitespace-nowrap sm:text-ellipsis sm:overflow-hidden sm:max-w-160">
|
||||
{item.name}
|
||||
</span>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export const HistoryChart: React.FC<Props> = ({ question }) => {
|
||||
// maybe use context instead?
|
||||
const [highlight, setHighlight] = useState<number | undefined>(undefined);
|
||||
|
|
Loading…
Reference in New Issue
Block a user