// PricingChart.jsx
import React, { useState, useEffect, useRef } from 'react';
import { useScrollToTop } from '../hooks/useScrollToTop';
import '../styles/PricingChart.css';
const ChartLegend = ({ onLegendClick, highlightedBarTypes, showPricing = true }) => {
if (!showPricing) return null;
return (
onLegendClick('input')}
style={{ cursor: 'pointer', opacity: highlightedBarTypes.input ? 1 : 0.5 }}
>
Input Price
onLegendClick('output')}
style={{ cursor: 'pointer', opacity: highlightedBarTypes.output ? 1 : 0.5 }}
>
Output Price
);
};
const ChartBar = ({ price, type, maxPrice, highlighted, score }) => {
const getBarHeight = () => {
if (score !== undefined) {
return (score / maxPrice) * 200;
}
return (price / maxPrice) * 200;
};
return (
{score !== undefined ? score : price}
);
};
const ProviderColumn = ({ provider, maxPrice, highlightedBarTypes, showPricing = true }) => (
{showPricing ? (
<>
>
) : (
)}
{provider.name}
);
const YAxis = ({ maxPrice }) => {
const numberOfTicks = 5;
const tickValues = [];
for (let i = 0; i <= numberOfTicks; i++) {
const value = ((maxPrice / numberOfTicks) * i).toFixed(2);
tickValues.push(value);
}
return (
{tickValues.reverse().map((value, index) => (
{value}
))}
);
};
const GridLines = () => (
{[...Array(5)].map((_, index) => (
))}
);
const PricingChart = ({ data, showPricing = true }) => {
useScrollToTop();
const [highlightedBarTypes, setHighlightedBarTypes] = useState({
input: true,
output: true,
});
const chartAreaRef = useRef(null);
const [hasScroll, setHasScroll] = useState(false);
const [showScrollHint, setShowScrollHint] = useState(false);
useEffect(() => {
const checkScroll = () => {
if (chartAreaRef.current) {
const { scrollWidth, clientWidth, scrollLeft } = chartAreaRef.current;
setHasScroll(scrollWidth > clientWidth);
// 只在滚动到最左侧时显示提示
setShowScrollHint(scrollWidth > clientWidth && scrollLeft === 0);
}
};
const handleScroll = () => {
if (chartAreaRef.current) {
const { scrollLeft } = chartAreaRef.current;
// 当用户开始滚动时隐藏提示
if (scrollLeft > 0) {
setShowScrollHint(false);
}
}
};
checkScroll();
window.addEventListener('resize', checkScroll);
if (chartAreaRef.current) {
chartAreaRef.current.addEventListener('scroll', handleScroll);
}
return () => {
window.removeEventListener('resize', checkScroll);
if (chartAreaRef.current) {
chartAreaRef.current.removeEventListener('scroll', handleScroll);
}
};
}, [data]);
const handleScrollHintClick = () => {
if (chartAreaRef.current) {
const { scrollWidth, clientWidth } = chartAreaRef.current;
chartAreaRef.current.scrollTo({
left: scrollWidth - clientWidth,
behavior: 'smooth'
});
setShowScrollHint(false);
}
};
const handleLegendClick = (barType) => {
setHighlightedBarTypes((prevState) => ({
...prevState,
[barType]: !prevState[barType],
}));
};
const getMaxPrice = () => {
if (!showPricing) {
return Math.max(...data.providers.map(provider => provider.score));
}
const prices = data.providers.flatMap((provider) => [
provider.inputPrice,
provider.outputPrice,
]);
return Math.max(...prices);
};
const maxPrice = getMaxPrice();
return (
{data.title}
{data.subtitle}
{data.providers.map((provider) => (
))}
{showScrollHint && (
)}
);
};
export default PricingChart;