在React.js中创建带半圆形Y轴的高尔夫击球散布图
实现半圆形Y轴高尔夫击球散布图方案
核心思路
因为Chart.js默认是笛卡尔坐标系,要实现类似练习场的半圆形布局,本质是把击球数据从「距离+左右偏移」转换成极坐标(距离=极径,左右偏移=极角),再映射到画布的笛卡尔坐标上,同时通过自定义插件绘制半圆形的练习场背景和刻度。
Chart.js + React 实现代码
首先安装依赖:
npm install chart.js react-chartjs-2
React组件代码:
import React from 'react'; import { Chart, registerables } from 'chart.js'; import { Scatter } from 'react-chartjs-2'; Chart.register(...registerables); // 自定义插件:绘制半圆形练习场背景与刻度 const semicircleFieldPlugin = { id: 'semicircleField', beforeDraw: (chart) => { const ctx = chart.ctx; const { width, height } = chart.canvas; const centerX = width / 2; const centerY = height; // 画布底部作为发球点 const maxDistance = 300; // 最大击球距离,根据你的实际数据调整 // 绘制半圆形练习场外轮廓 ctx.beginPath(); ctx.arc(centerX, centerY, maxDistance, Math.PI, 0); ctx.strokeStyle = '#ccc'; ctx.lineWidth = 2; ctx.stroke(); // 绘制距离刻度(同心圆) for (let d = 50; d <= maxDistance; d += 50) { ctx.beginPath(); ctx.arc(centerX, centerY, d, Math.PI, 0); ctx.strokeStyle = '#eee'; ctx.lineWidth = 1; ctx.stroke(); // 标注距离数值 ctx.fillStyle = '#666'; ctx.font = '12px Arial'; ctx.textAlign = 'center'; ctx.fillText(`${d}yd`, centerX, centerY - d - 5); } // 绘制左右方向刻度(射线) const angles = [-60, -30, 0, 30, 60]; // 自定义角度刻度 angles.forEach(angle => { const rad = (angle * Math.PI) / 180; const x = centerX + maxDistance * Math.sin(rad); const y = centerY - maxDistance * Math.cos(rad); // 绘制刻度线 ctx.beginPath(); ctx.moveTo(centerX, centerY); ctx.lineTo(x, y); ctx.strokeStyle = '#eee'; ctx.lineWidth = 1; ctx.stroke(); // 标注方向标签 ctx.fillStyle = '#666'; ctx.textAlign = angle < 0 ? 'right' : angle > 0 ? 'left' : 'center'; const labelX = angle === 0 ? x : x + (angle > 0 ? 5 : -5); ctx.fillText(angle === 0 ? '正前方' : `${Math.abs(angle)}°${angle < 0 ? '左' : '右'}`, labelX, y - 5); }); } }; const GolfShotScatter = () => { // 示例击球数据:distance=击球距离,offsetAngle=左右偏移角度(范围-90°到90°) const shotData = [ { distance: 250, offsetAngle: 10 }, { distance: 220, offsetAngle: -15 }, { distance: 280, offsetAngle: 5 }, { distance: 200, offsetAngle: 25 }, { distance: 260, offsetAngle: -8 }, ]; // 将极坐标数据转换为Chart.js散点图的笛卡尔坐标 const chartData = { datasets: [ { label: '击球落点', data: shotData.map(shot => { const centerX = chart.canvas.width / 2; const centerY = chart.canvas.height; const rad = (shot.offsetAngle * Math.PI) / 180; return { x: centerX + shot.distance * Math.sin(rad), y: centerY - shot.distance * Math.cos(rad), }; }), backgroundColor: '#ff5722', pointRadius: 6, pointHoverRadius: 8, }, ], }; const options = { responsive: true, maintainAspectRatio: false, plugins: { legend: { display: true }, title: { display: true, text: '高尔夫击球散布图' }, }, scales: { // 隐藏默认XY轴,使用自定义极坐标刻度 x: { display: false }, y: { display: false }, }, }; return ( <div style={{ width: '800px', height: '400px', margin: '0 auto' }}> <Scatter data={chartData} options={options} plugins={[semicircleFieldPlugin]} /> </div> ); }; export default GolfShotScatter;
数据适配说明
如果你的原始数据是「距离+左右偏移距离」(比如左侧10码、右侧5码),可以用下面的公式转换成角度:
// offsetDistance:左右偏移距离(左负右正),distance:击球距离 const offsetAngle = Math.atan2(offsetDistance, distance) * (180 / Math.PI);
备选方案:D3.js
如果需要更精细的自定义控制,D3.js对极坐标的支持更原生,你可以用d3.arc绘制半圆形背景,d3.scaleLinear映射距离和角度,直接在SVG上绘制散点和刻度,灵活性更高。
内容的提问来源于stack exchange,提问作者vinay
相关产品推荐
相关产品推荐

