feat: 优化折线图标签绘制,添加圆角矩形背景
This commit is contained in:
@@ -230,40 +230,68 @@ export default function FundTrendChart({ code, isExpanded, onToggleExpand, trans
|
||||
const datasets = chart.data.datasets;
|
||||
const primaryColor = getComputedStyle(document.documentElement).getPropertyValue('--primary').trim() || '#22d3ee';
|
||||
|
||||
// Helper function to draw point label
|
||||
// 绘制圆角矩形(兼容无 roundRect 的环境)
|
||||
const drawRoundRect = (left, top, w, h, r) => {
|
||||
const rad = Math.min(r, w / 2, h / 2);
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(left + rad, top);
|
||||
ctx.lineTo(left + w - rad, top);
|
||||
ctx.quadraticCurveTo(left + w, top, left + w, top + rad);
|
||||
ctx.lineTo(left + w, top + h - rad);
|
||||
ctx.quadraticCurveTo(left + w, top + h, left + w - rad, top + h);
|
||||
ctx.lineTo(left + rad, top + h);
|
||||
ctx.quadraticCurveTo(left, top + h, left, top + h - rad);
|
||||
ctx.lineTo(left, top + rad);
|
||||
ctx.quadraticCurveTo(left, top, left + rad, top);
|
||||
ctx.closePath();
|
||||
};
|
||||
|
||||
const drawPointLabel = (datasetIndex, index, text, bgColor, textColor = '#ffffff', yOffset = 0) => {
|
||||
const meta = chart.getDatasetMeta(datasetIndex);
|
||||
if (!meta.data[index]) return;
|
||||
const element = meta.data[index];
|
||||
// Check if element is visible/not skipped
|
||||
if (element.skip) return;
|
||||
|
||||
const x = element.x;
|
||||
const y = element.y + yOffset;
|
||||
const paddingH = 10;
|
||||
const paddingV = 6;
|
||||
const radius = 8;
|
||||
|
||||
ctx.save();
|
||||
ctx.font = 'bold 11px sans-serif';
|
||||
const labelWidth = ctx.measureText(text).width + 12;
|
||||
const textW = ctx.measureText(text).width;
|
||||
const w = textW + paddingH * 2;
|
||||
const h = 18;
|
||||
const left = x - w / 2;
|
||||
const top = y - 24;
|
||||
|
||||
// Draw label above the point
|
||||
drawRoundRect(left, top, w, h, radius);
|
||||
ctx.globalAlpha = 0.7;
|
||||
ctx.fillStyle = bgColor;
|
||||
ctx.fillRect(x - labelWidth/2, y - 24, labelWidth, 18);
|
||||
ctx.fill();
|
||||
|
||||
ctx.globalAlpha = 0.7;
|
||||
ctx.fillStyle = textColor;
|
||||
ctx.textAlign = 'center';
|
||||
ctx.textBaseline = 'middle';
|
||||
ctx.fillText(text, x, y - 15);
|
||||
ctx.fillText(text, x, top + h / 2);
|
||||
ctx.restore();
|
||||
};
|
||||
|
||||
// 1. Draw default labels for first buy and sell points
|
||||
// Resolve active elements (hover/focus) first — used to decide whether to show default labels
|
||||
let activeElements = [];
|
||||
if (chart.tooltip?._active?.length) {
|
||||
activeElements = chart.tooltip._active;
|
||||
} else {
|
||||
activeElements = chart.getActiveElements();
|
||||
}
|
||||
|
||||
// 1. Draw default labels for first buy and sell points only when NOT focused/hovering
|
||||
// Index 1 is Buy, Index 2 is Sell
|
||||
if (datasets[1] && datasets[1].data) {
|
||||
if (!activeElements?.length && datasets[1] && datasets[1].data) {
|
||||
const firstBuyIndex = datasets[1].data.findIndex(v => v !== null && v !== undefined);
|
||||
if (firstBuyIndex !== -1) {
|
||||
// Check collision with Sell
|
||||
let sellIndex = -1;
|
||||
if (datasets[2] && datasets[2].data) {
|
||||
sellIndex = datasets[2].data.findIndex(v => v !== null && v !== undefined);
|
||||
@@ -272,7 +300,7 @@ export default function FundTrendChart({ code, isExpanded, onToggleExpand, trans
|
||||
drawPointLabel(1, firstBuyIndex, '买入', primaryColor, '#ffffff', isCollision ? -20 : 0);
|
||||
}
|
||||
}
|
||||
if (datasets[2] && datasets[2].data) {
|
||||
if (!activeElements?.length && datasets[2] && datasets[2].data) {
|
||||
const firstSellIndex = datasets[2].data.findIndex(v => v !== null && v !== undefined);
|
||||
if (firstSellIndex !== -1) {
|
||||
drawPointLabel(2, firstSellIndex, '卖出', '#f87171');
|
||||
@@ -280,13 +308,6 @@ export default function FundTrendChart({ code, isExpanded, onToggleExpand, trans
|
||||
}
|
||||
|
||||
// 2. Handle active elements (hover crosshair)
|
||||
let activeElements = [];
|
||||
if (chart.tooltip?._active?.length) {
|
||||
activeElements = chart.tooltip._active;
|
||||
} else {
|
||||
activeElements = chart.getActiveElements();
|
||||
}
|
||||
|
||||
if (activeElements && activeElements.length) {
|
||||
const activePoint = activeElements[0];
|
||||
const x = activePoint.element.x;
|
||||
|
||||
4
package-lock.json
generated
4
package-lock.json
generated
@@ -1,12 +1,12 @@
|
||||
{
|
||||
"name": "real-time-fund",
|
||||
"version": "0.1.5",
|
||||
"version": "0.1.6",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "real-time-fund",
|
||||
"version": "0.1.5",
|
||||
"version": "0.1.6",
|
||||
"dependencies": {
|
||||
"@dicebear/collection": "^9.3.1",
|
||||
"@dicebear/core": "^9.3.1",
|
||||
|
||||
Reference in New Issue
Block a user