当前位置:首页 > JavaScript

原生js实现饼图

2026-01-31 04:32:10JavaScript

使用Canvas绘制饼图

在HTML中创建<canvas>元素作为绘图区域,通过JavaScript计算数据比例并绘制扇形。

<canvas id="pieChart" width="400" height="400"></canvas>
function drawPieChart(data) {
  const canvas = document.getElementById('pieChart');
  const ctx = canvas.getContext('2d');
  const total = data.reduce((sum, item) => sum + item.value, 0);
  let startAngle = 0;

  data.forEach((item, index) => {
    const sliceAngle = (item.value / total) * 2 * Math.PI;
    ctx.beginPath();
    ctx.fillStyle = item.color || getRandomColor();
    ctx.moveTo(200, 200);
    ctx.arc(200, 200, 150, startAngle, startAngle + sliceAngle);
    ctx.closePath();
    ctx.fill();
    startAngle += sliceAngle;
  });
}

function getRandomColor() {
  return `#${Math.floor(Math.random()*16777215).toString(16)}`;
}

// 示例数据
const chartData = [
  { value: 30, color: '#FF6384' },
  { value: 50, color: '#36A2EB' },
  { value: 20, color: '#FFCE56' }
];

drawPieChart(chartData);

添加交互效果

为饼图添加鼠标悬停高亮效果,通过检测鼠标位置是否在扇形区域内实现交互。

原生js实现饼图

canvas.addEventListener('mousemove', (e) => {
  const rect = canvas.getBoundingClientRect();
  const x = e.clientX - rect.left - 200;
  const y = e.clientY - rect.top - 200;
  const distance = Math.sqrt(x*x + y*y);

  if (distance <= 150) {
    const angle = Math.atan2(y, x);
    let cumulativeAngle = 0;

    data.forEach((item, index) => {
      const sliceAngle = (item.value / total) * 2 * Math.PI;
      if (angle >= cumulativeAngle && angle < cumulativeAngle + sliceAngle) {
        // 高亮处理逻辑
      }
      cumulativeAngle += sliceAngle;
    });
  }
});

添加图例和标签

在饼图旁添加说明性文字,显示各数据项的名称和占比。

原生js实现饼图

function drawLegend() {
  const legend = document.createElement('div');
  legend.style.display = 'flex';
  legend.style.flexDirection = 'column';

  data.forEach(item => {
    const legendItem = document.createElement('div');
    legendItem.style.display = 'flex';
    legendItem.style.alignItems = 'center';

    const colorBox = document.createElement('div');
    colorBox.style.width = '20px';
    colorBox.style.height = '20px';
    colorBox.style.backgroundColor = item.color;
    colorBox.style.marginRight = '10px';

    const label = document.createElement('span');
    label.textContent = `${item.name}: ${((item.value/total)*100).toFixed(1)}%`;

    legendItem.appendChild(colorBox);
    legendItem.appendChild(label);
    legend.appendChild(legendItem);
  });

  document.body.appendChild(legend);
}

响应式调整

监听窗口大小变化事件,动态调整饼图尺寸。

function resizeCanvas() {
  const container = canvas.parentElement;
  const size = Math.min(container.clientWidth, container.clientHeight) * 0.8;
  canvas.width = size;
  canvas.height = size;
  drawPieChart(data);
}

window.addEventListener('resize', resizeCanvas);
resizeCanvas();

动画效果实现

为饼图添加加载动画效果,使用requestAnimationFrame逐步绘制。

function animatePieChart() {
  let progress = 0;
  const duration = 1000; // 动画持续时间(ms)
  const startTime = performance.now();

  function frame(timestamp) {
    progress = Math.min((timestamp - startTime) / duration, 1);
    ctx.clearRect(0, 0, canvas.width, canvas.height);

    let currentAngle = 0;
    data.forEach(item => {
      const endAngle = currentAngle + (item.value / total) * 2 * Math.PI * progress;
      ctx.beginPath();
      ctx.fillStyle = item.color;
      ctx.moveTo(200, 200);
      ctx.arc(200, 200, 150, currentAngle, endAngle);
      ctx.closePath();
      ctx.fill();
      currentAngle = endAngle;
    });

    if (progress < 1) requestAnimationFrame(frame);
  }

  requestAnimationFrame(frame);
}

注意事项

  • 确保数据总和不为零,否则会导致计算比例时出现除零错误
  • 对于大量数据项,建议合并小比例项目为"其他"类别
  • 考虑添加过渡动画时注意性能影响
  • 移动端需要额外处理触摸事件

标签: js
分享给朋友:

相关文章

js实现分页

js实现分页

分页的基本实现思路 在JavaScript中实现分页功能通常需要结合前端和后端逻辑。前端负责渲染分页控件和处理用户交互,后端负责提供分页数据。 前端分页实现 纯前端分页适用于数据量较小的情况,可以直…

js实现图片放大缩小

js实现图片放大缩小

实现图片放大缩小的基础方法 使用CSS的transform: scale()属性可以快速实现图片的放大缩小效果。通过JavaScript动态修改该属性值: const img = document…

js实现报表

js实现报表

使用JavaScript实现报表 在JavaScript中实现报表功能可以通过多种方式完成,常见的方法包括使用原生JavaScript、第三方库(如Chart.js、D3.js)或结合后端数据渲染。以…

js画图实现

js画图实现

使用Canvas API绘制图形 Canvas是HTML5提供的绘图API,通过JavaScript操作Canvas元素可以绘制各种图形。以下是一个简单的示例: <canvas id="myC…

js实现投球

js实现投球

实现投球动画的基本思路 使用JavaScript和CSS动画结合的方式模拟投球效果。核心是通过改变元素的位置、旋转和缩放属性,配合定时器或CSS过渡实现平滑动画。 创建基础HTML结构 <d…

js实现文字滚动

js实现文字滚动

实现文字滚动的几种方法 使用CSS动画实现滚动 通过CSS的@keyframes和transform属性可以实现平滑的文字滚动效果。 <style> .scroll-text { w…