当前位置:首页 > 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实现文件下载

使用 a 标签下载文件 通过动态创建 a 标签并设置 download 属性实现文件下载。适用于已知文件 URL 或 Blob 数据的情况。 function downloadFile(url, f…

js实现复制功能

js实现复制功能

使用 document.execCommand 方法 这种方法适用于较旧的浏览器,但在现代浏览器中可能被逐步淘汰。通过创建一个临时的 textarea 元素,将文本内容放入其中,然后执行复制命令。…

js实现图片预览

js实现图片预览

使用FileReader API实现图片预览 通过FileReader对象读取用户选择的图片文件并显示预览: const input = document.getElementById('image…

js jquery

js jquery

jQuery 简介 jQuery 是一个快速、简洁的 JavaScript 库,简化了 HTML 文档遍历、事件处理、动画设计和 Ajax 交互。它兼容多种浏览器,提供易于使用的 API,使开发者能够…

js实现滑动

js实现滑动

实现滑动效果的方法 在JavaScript中实现滑动效果可以通过多种方式完成,以下是几种常见的实现方法: 使用CSS过渡和JavaScript触发 通过CSS定义过渡效果,JavaScript控制触…

js实现排序

js实现排序

数组排序方法 JavaScript提供了内置的sort()方法用于数组排序。默认情况下,sort()将元素转换为字符串并按照Unicode码点排序。对于数字排序,需传入比较函数。 const num…