From 194f9246ef0171aa4f9f241f4ec506260de89b0b Mon Sep 17 00:00:00 2001 From: hzm <934585316@qq.com> Date: Tue, 24 Feb 2026 21:36:56 +0800 Subject: [PATCH 1/3] =?UTF-8?q?feat:=20y=E8=BD=B4=E5=9D=90=E6=A0=87?= =?UTF-8?q?=E6=94=B9=E4=B8=BA=E5=B7=A6=E4=BE=A7=E5=B1=95=E7=A4=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/components/FundIntradayChart.jsx | 51 ++++++++++++++++++++++++---- app/components/FundTrendChart.jsx | 45 +++++++++++++++++++++--- 2 files changed, 84 insertions(+), 12 deletions(-) diff --git a/app/components/FundIntradayChart.jsx b/app/components/FundIntradayChart.jsx index 4d11516..24748cd 100644 --- a/app/components/FundIntradayChart.jsx +++ b/app/components/FundIntradayChart.jsx @@ -1,6 +1,6 @@ 'use client'; -import { useMemo } from 'react'; +import { useMemo, useRef, useEffect } from 'react'; import { Chart as ChartJS, CategoryScale, @@ -27,6 +27,9 @@ ChartJS.register( * referenceNav: 参考净值(最新单位净值),用于计算涨跌幅;未传则用当日第一个估值作为参考。 */ export default function FundIntradayChart({ series = [], referenceNav }) { + const chartRef = useRef(null); + const hoverTimeoutRef = useRef(null); + const chartData = useMemo(() => { if (!series.length) return { labels: [], datasets: [] }; const labels = series.map((d) => d.time); @@ -91,7 +94,7 @@ export default function FundIntradayChart({ series = [], referenceNav }) { }, y: { display: true, - position: 'right', + position: 'left', grid: { color: '#1f2937', drawBorder: false }, ticks: { color: '#9ca3af', @@ -100,11 +103,45 @@ export default function FundIntradayChart({ series = [], referenceNav }) { } } }, - onHover: (event, chartElement) => { - event.native.target.style.cursor = chartElement[0] ? 'crosshair' : 'default'; + onHover: (event, chartElement, chart) => { + const target = event?.native?.target; + if (target) { + target.style.cursor = chartElement[0] ? 'crosshair' : 'default'; + } + + const currentChart = chart || chartRef.current; + if (!currentChart) return; + + if (hoverTimeoutRef.current) { + clearTimeout(hoverTimeoutRef.current); + hoverTimeoutRef.current = null; + } + + if (chartElement[0]) { + hoverTimeoutRef.current = setTimeout(() => { + const c = chartRef.current || currentChart; + if (!c) return; + c.setActiveElements([]); + if (c.tooltip) { + c.tooltip.setActiveElements([], { x: 0, y: 0 }); + } + c.update(); + if (target) { + target.style.cursor = 'default'; + } + }, 2000); + } } }), []); + useEffect(() => { + return () => { + if (hoverTimeoutRef.current) { + clearTimeout(hoverTimeoutRef.current); + } + }; + }, []); + const plugins = useMemo(() => [{ id: 'crosshair', afterDraw: (chart) => { @@ -157,9 +194,9 @@ export default function FundIntradayChart({ series = [], referenceNav }) { const valueStr = typeof val === 'number' ? `${val >= 0 ? '+' : ''}${val.toFixed(2)}%` : String(val); const vw = ctx.measureText(valueStr).width + 8; ctx.fillStyle = prim; - ctx.fillRect(rightX - vw, y - 8, vw, 16); + ctx.fillRect(leftX, y - 8, vw, 16); ctx.fillStyle = bgText; - ctx.fillText(valueStr, rightX - vw / 2, y); + ctx.fillText(valueStr, leftX + vw / 2, y); } ctx.restore(); } @@ -191,7 +228,7 @@ export default function FundIntradayChart({ series = [], referenceNav }) { {displayDate && 估值日期 {displayDate}}
- +
); diff --git a/app/components/FundTrendChart.jsx b/app/components/FundTrendChart.jsx index f8edc06..3a6a45d 100644 --- a/app/components/FundTrendChart.jsx +++ b/app/components/FundTrendChart.jsx @@ -35,6 +35,7 @@ export default function FundTrendChart({ code, isExpanded, onToggleExpand, trans const [loading, setLoading] = useState(false); const [error, setError] = useState(null); const chartRef = useRef(null); + const hoverTimeoutRef = useRef(null); useEffect(() => { // If collapsed, don't fetch data unless we have no data yet @@ -198,7 +199,7 @@ export default function FundTrendChart({ code, isExpanded, onToggleExpand, trans }, y: { display: true, - position: 'right', + position: 'left', grid: { color: '#1f2937', drawBorder: false, @@ -217,8 +218,42 @@ export default function FundTrendChart({ code, isExpanded, onToggleExpand, trans mode: 'index', intersect: false, }, - onHover: (event, chartElement) => { - event.native.target.style.cursor = chartElement[0] ? 'crosshair' : 'default'; + onHover: (event, chartElement, chart) => { + const target = event?.native?.target; + if (target) { + target.style.cursor = chartElement[0] ? 'crosshair' : 'default'; + } + + const currentChart = chart || chartRef.current; + if (!currentChart) return; + + if (hoverTimeoutRef.current) { + clearTimeout(hoverTimeoutRef.current); + hoverTimeoutRef.current = null; + } + + if (chartElement[0]) { + hoverTimeoutRef.current = setTimeout(() => { + const c = chartRef.current || currentChart; + if (!c) return; + c.setActiveElements([]); + if (c.tooltip) { + c.tooltip.setActiveElements([], { x: 0, y: 0 }); + } + c.update(); + if (target) { + target.style.cursor = 'default'; + } + }, 2000); + } + } + }; + }, []); + + useEffect(() => { + return () => { + if (hoverTimeoutRef.current) { + clearTimeout(hoverTimeoutRef.current); } }; }, []); @@ -360,10 +395,10 @@ export default function FundTrendChart({ code, isExpanded, onToggleExpand, trans const valueStr = (typeof value === 'number' ? value.toFixed(2) : value) + '%'; const valWidth = ctx.measureText(valueStr).width + 8; ctx.fillStyle = primaryColor; - ctx.fillRect(rightX - valWidth, y - 8, valWidth, 16); + ctx.fillRect(leftX, y - 8, valWidth, 16); ctx.fillStyle = '#0f172a'; // --background ctx.textAlign = 'center'; - ctx.fillText(valueStr, rightX - valWidth / 2, y); + ctx.fillText(valueStr, leftX + valWidth / 2, y); } } From 42327fc110e86b534c29e8035801a8db918322d6 Mon Sep 17 00:00:00 2001 From: hzm <934585316@qq.com> Date: Tue, 24 Feb 2026 22:05:11 +0800 Subject: [PATCH 2/3] =?UTF-8?q?feat:=20=E6=8A=98=E7=BA=BF=E5=9B=BE2?= =?UTF-8?q?=E7=A7=92=E5=90=8E=E8=87=AA=E5=8A=A8=E5=A4=B1=E7=84=A6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/components/FundIntradayChart.jsx | 19 +++++++++---- app/components/FundTrendChart.jsx | 40 +++++++++++++++++----------- 2 files changed, 39 insertions(+), 20 deletions(-) diff --git a/app/components/FundIntradayChart.jsx b/app/components/FundIntradayChart.jsx index 24748cd..6fb79a9 100644 --- a/app/components/FundIntradayChart.jsx +++ b/app/components/FundIntradayChart.jsx @@ -105,19 +105,28 @@ export default function FundIntradayChart({ series = [], referenceNav }) { }, onHover: (event, chartElement, chart) => { const target = event?.native?.target; - if (target) { - target.style.cursor = chartElement[0] ? 'crosshair' : 'default'; - } - const currentChart = chart || chartRef.current; if (!currentChart) return; + const tooltipActive = currentChart.tooltip?._active ?? []; + const activeElements = currentChart.getActiveElements + ? currentChart.getActiveElements() + : []; + const hasActive = + (chartElement && chartElement.length > 0) || + (tooltipActive && tooltipActive.length > 0) || + (activeElements && activeElements.length > 0); + + if (target) { + target.style.cursor = hasActive ? 'crosshair' : 'default'; + } + if (hoverTimeoutRef.current) { clearTimeout(hoverTimeoutRef.current); hoverTimeoutRef.current = null; } - if (chartElement[0]) { + if (hasActive) { hoverTimeoutRef.current = setTimeout(() => { const c = chartRef.current || currentChart; if (!c) return; diff --git a/app/components/FundTrendChart.jsx b/app/components/FundTrendChart.jsx index 3a6a45d..56acd9d 100644 --- a/app/components/FundTrendChart.jsx +++ b/app/components/FundTrendChart.jsx @@ -220,10 +220,25 @@ export default function FundTrendChart({ code, isExpanded, onToggleExpand, trans }, onHover: (event, chartElement, chart) => { const target = event?.native?.target; + const currentChart = chart || chartRef.current; + if (!currentChart) return; + + const tooltipActive = currentChart.tooltip?._active ?? []; + const activeElements = currentChart.getActiveElements + ? currentChart.getActiveElements() + : []; + const hasActive = + (chartElement && chartElement.length > 0) || + (tooltipActive && tooltipActive.length > 0) || + (activeElements && activeElements.length > 0); + if (target) { - target.style.cursor = chartElement[0] ? 'crosshair' : 'default'; + target.style.cursor = hasActive ? 'crosshair' : 'default'; } + // 仅用于桌面端 hover 改变光标,不在这里做 2 秒清除,避免移动端 hover 事件不稳定 + }, + onClick: (_event, _elements, chart) => { const currentChart = chart || chartRef.current; if (!currentChart) return; @@ -232,20 +247,15 @@ export default function FundTrendChart({ code, isExpanded, onToggleExpand, trans hoverTimeoutRef.current = null; } - if (chartElement[0]) { - hoverTimeoutRef.current = setTimeout(() => { - const c = chartRef.current || currentChart; - if (!c) return; - c.setActiveElements([]); - if (c.tooltip) { - c.tooltip.setActiveElements([], { x: 0, y: 0 }); - } - c.update(); - if (target) { - target.style.cursor = 'default'; - } - }, 2000); - } + hoverTimeoutRef.current = setTimeout(() => { + const c = chartRef.current || currentChart; + if (!c) return; + c.setActiveElements([]); + if (c.tooltip) { + c.tooltip.setActiveElements([], { x: 0, y: 0 }); + } + c.update(); + }, 2000); } }; }, []); From 048bd8db57800a7afb307ba63c2fb5c3b554788b Mon Sep 17 00:00:00 2001 From: hzm <934585316@qq.com> Date: Tue, 24 Feb 2026 23:03:03 +0800 Subject: [PATCH 3/3] =?UTF-8?q?feat:=20=E5=AE=8C=E5=96=84=E6=8A=98?= =?UTF-8?q?=E7=BA=BF=E5=9B=BE2=E7=A7=92=E5=90=8E=E8=87=AA=E5=8A=A8?= =?UTF-8?q?=E5=A4=B1=E7=84=A6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/components/FundTrendChart.jsx | 41 +++++++++++++++++-------------- 1 file changed, 22 insertions(+), 19 deletions(-) diff --git a/app/components/FundTrendChart.jsx b/app/components/FundTrendChart.jsx index 56acd9d..2cefd7c 100644 --- a/app/components/FundTrendChart.jsx +++ b/app/components/FundTrendChart.jsx @@ -238,25 +238,7 @@ export default function FundTrendChart({ code, isExpanded, onToggleExpand, trans // 仅用于桌面端 hover 改变光标,不在这里做 2 秒清除,避免移动端 hover 事件不稳定 }, - onClick: (_event, _elements, chart) => { - const currentChart = chart || chartRef.current; - if (!currentChart) return; - - if (hoverTimeoutRef.current) { - clearTimeout(hoverTimeoutRef.current); - hoverTimeoutRef.current = null; - } - - hoverTimeoutRef.current = setTimeout(() => { - const c = chartRef.current || currentChart; - if (!c) return; - c.setActiveElements([]); - if (c.tooltip) { - c.tooltip.setActiveElements([], { x: 0, y: 0 }); - } - c.update(); - }, 2000); - } + onClick: () => {} }; }, []); @@ -270,6 +252,27 @@ export default function FundTrendChart({ code, isExpanded, onToggleExpand, trans const plugins = useMemo(() => [{ id: 'crosshair', + afterEvent: (chart, args) => { + const { event, replay } = args || {}; + if (!event || replay) return; // 忽略动画重放 + + const type = event.type; + if (type === 'mousemove' || type === 'click') { + if (hoverTimeoutRef.current) { + clearTimeout(hoverTimeoutRef.current); + hoverTimeoutRef.current = null; + } + + hoverTimeoutRef.current = setTimeout(() => { + if (!chart) return; + chart.setActiveElements([]); + if (chart.tooltip) { + chart.tooltip.setActiveElements([], { x: 0, y: 0 }); + } + chart.update(); + }, 2000); + } + }, afterDraw: (chart) => { const ctx = chart.ctx; const datasets = chart.data.datasets;