You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Chart.js中实现折线图框选范围并获取X轴区间

折线图区域选择与X轴范围获取实现方案

问题描述

需要在折线图上实现以下功能:

  • 鼠标按下并向右拖动时生成矩形选框
  • 释放鼠标后获取选框对应的X轴起止范围,用于更新其他图表
  • 选框在释放鼠标后自动消失

现有代码

HTML结构

<div class="card mb-4 ">
  <div class="card-header">
    <i class="fa fa-area-chart me-1"></i>
    Frequency vs Acceleration
  </div>
  <div class="card-body">
    <canvas id="myLineChart" width="100%" height="30"></canvas>
  </div>
  <div class="card-footer small text-muted">
    Updated on {{chartUpdateTime|date:'mediumDate'}} at {{chartUpdateTime|date:'shortTime'}}
  </div>
</div>

TypeScript图表初始化代码

ngOnInit():void{
  var myLineChart = new Chart('myLineChart', {
    type: 'line',
    data: {
      labels: ["0Hz", "20Hz", "40Hz", "60Hz", "80Hz", "100Hz", "120Hz", "140Hz", "160Hz", "180Hz"],
      datasets: [{
        label: 'Frequency',
        tension:0.4,
        backgroundColor: 'rgba(0,120,214,1)',
        borderColor: 'rgba(0,120,214,1)',
        pointRadius: 3,
        pointBackgroundColor: 'rgba(0,120,214,1)',
        pointHoverRadius: 4,
        pointHoverBackgroundColor: 'rgba(0,120,214,1)',
        pointHitRadius: 50,
        pointBorderWidth: 2,
        data: [10000, 30162, 26263, 18394, 18287, 28682, 31274, 33259, 25849, 24159],
      }],
    },
    options: {
      scales: {
        xAxis:{
          grid:{ display:false },
          ticks:{ maxTicksLimit:7 }
        },
        yAxis:{
          ticks:{ maxTicksLimit:5 },
          grid:{ color: "rgba(0, 0, 0, .125)" }
        }
      }
    }
  });
}

当前图表效果

当前折线图效果

解决方案

方案一:基于Chart.js原生事件实现

通过监听canvas鼠标事件,手动绘制选框并将像素坐标转换为X轴刻度值,代码修改如下:

ngOnInit(): void {
  const canvas = document.getElementById('myLineChart') as HTMLCanvasElement;
  const ctx = canvas.getContext('2d');
  let isDragging = false;
  let startX = 0;
  let endX = 0;
  let chartInstance: Chart;

  // 初始化图表
  chartInstance = new Chart('myLineChart', {
    type: 'line',
    data: {
      labels: ["0Hz", "20Hz", "40Hz", "60Hz", "80Hz", "100Hz", "120Hz", "140Hz", "160Hz", "180Hz"],
      datasets: [{
        label: 'Frequency',
        tension: 0.4,
        backgroundColor: 'rgba(0,120,214,1)',
        borderColor: 'rgba(0,120,214,1)',
        pointRadius: 3,
        pointBackgroundColor: 'rgba(0,120,214,1)',
        pointHoverRadius: 4,
        pointHoverBackgroundColor: 'rgba(0,120,214,1)',
        pointHitRadius: 50,
        pointBorderWidth: 2,
        data: [10000, 30162, 26263, 18394, 18287, 28682, 31274, 33259, 25849, 24159],
      }],
    },
    options: {
      scales: {
        xAxis: {
          grid: { display: false },
          ticks: { maxTicksLimit: 7 }
        },
        yAxis: {
          ticks: { maxTicksLimit: 5 },
          grid: { color: "rgba(0, 0, 0, .125)" }
        }
      }
    }
  });

  // 鼠标按下:记录起始位置
  canvas.addEventListener('mousedown', (e) => {
    isDragging = true;
    const rect = canvas.getBoundingClientRect();
    startX = e.clientX - rect.left;
  });

  // 鼠标移动:绘制选框
  canvas.addEventListener('mousemove', (e) => {
    if (!isDragging) return;
    const rect = canvas.getBoundingClientRect();
    endX = e.clientX - rect.left;
    
    // 清除画布并重绘图表
    chartInstance.clear();
    chartInstance.draw();
    
    // 绘制半透明选框
    ctx!.fillStyle = 'rgba(0,120,214,0.2)';
    const xStart = Math.min(startX, endX);
    const xWidth = Math.abs(endX - startX);
    ctx!.fillRect(xStart, 0, xWidth, canvas.height);
  });

  // 鼠标释放:计算X轴范围并更新其他图表
  canvas.addEventListener('mouseup', () => {
    if (!isDragging) return;
    isDragging = false;
    
    // 将像素坐标转换为X轴刻度值
    const xAxis = chartInstance.scales.x;
    const startValue = xAxis.getValueForPixel(Math.min(startX, endX));
    const endValue = xAxis.getValueForPixel(Math.max(startX, endX));
    
    // 此处调用你的其他图表更新逻辑,传入startValue和endValue
    console.log('选中的X轴范围:', startValue, endValue);
    
    // 清除选框并重绘图表
    chartInstance.clear();
    chartInstance.draw();
  });

  // 鼠标离开画布:取消拖动并清除选框
  canvas.addEventListener('mouseleave', () => {
    if (isDragging) {
      isDragging = false;
      chartInstance.clear();
      chartInstance.draw();
    }
  });
}

方案二:使用Chart.js插件简化实现

使用chartjs-plugin-zoom插件,支持区域选择与缩放,配置后可直接获取选中范围:

  1. 安装插件
npm install chartjs-plugin-zoom
  1. 修改图表配置
import zoomPlugin from 'chartjs-plugin-zoom';

// 注册插件
Chart.register(zoomPlugin);

// 图表options中添加zoom配置
options: {
  plugins: {
    zoom: {
      pan: { enabled: false },
      zoom: {
        enabled: true,
        mode: 'x',
        onZoomComplete: (chart) => {
          const xAxis = chart.scales.x;
          console.log('选中的X轴范围:', xAxis.min, xAxis.max);
          // 调用其他图表更新逻辑
        }
      }
    }
  },
  // 原有scales配置...
}

替代图表库推荐

如果觉得Chart.js实现不够简便,推荐以下免费开源图表库:

  • ECharts:内置dataZoom组件,支持矩形选框选择X轴范围,自带事件回调获取选中区间,文档完善,集成成本低。
  • Plotly.js:支持交互式框选,通过relayout事件可获取选中的X轴范围,适合复杂交互场景。

内容的提问来源于stack exchange,提问作者Shubham CSE

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.19 02:10:35