SVG数据可视化组件基础教程:带刻度的仪表盘

大家好,我是设计师邱兴,一个学习前端的设计师,今天给大家制作一个用SVG实现的带刻度的仪表盘,SVG相较于E chart来说制作简单,但是效果可以非常丰富。

一、目标

通过SVG和JavaScript实现一个圆形仪表盘进度条,包含以下功能:

  1. 圆形上有20个色块,初始透明度为0.3。
  2. 使用滑块动态调整进度,根据进度值改变色块的透明度。
  3. 显示当前进度百分比和进度值。

二、所需工具与准备

  1. 工具
    • 一个文本编辑器(如Notepad++、Hbuild等)。
    • 浏览器(用于预览效果)。
  2. 基础准备
    • 确保你对HTML、CSS和JavaScript有一定的了解。
    • 确保你对SVG的基本语法有一定了解。

三、代码分析与操作步骤

1. 创建HTML结构

首先,创建一个HTML文件,并设置基本的HTML结构:

html 复制代码
<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8">
  <title>SVG 带刻度的仪表盘</title>
  <style>
    /* 样式部分 */
  </style>
</head>
<body>
  <!-- SVG带刻度的仪表盘 -->
  <div class="gauge-container">
    <svg id="gauge" width="320" height="320" viewBox="0 0 320 320">
      <!-- 色块组 -->
      <g id="blocks"></g>
      <!-- 中心圆形装饰 -->
      <circle cx="160" cy="160" r="90" fill="#fff"/>
      <!-- 进度文本 -->
      <text id="progressText" x="160" y="175" text-anchor="middle" font-size="48" fill="#333" font-weight="bold">0%</text>
    </svg>
  </div>
  <!-- 滑块容器 -->
  <div class="slider-container">
    <input type="range" id="progressSlider" min="0" max="20" value="0" />
    <div>进度:<span id="progressNum">0</span>/20</div>
  </div>

  <script>
    // JavaScript部分
  </script>
</body>
</html>

2. 添加CSS样式

<style>标签中,添加以下CSS样式:

css 复制代码
body {
  background: #f8f8f8;
  display: flex;
  flex-direction: column;
  align-items: center;
  font-family: Arial, sans-serif;
}
.gauge-container {
  margin-top: 40px;
  margin-bottom: 20px;
}
.progress-value {
  font-size: 2em;
  font-weight: bold;
  text-align: center;
  margin-top: -60px;
  color: #333;
  user-select: none;
}
.slider-container {
  margin-top: 30px;
  text-align: center;
}
  • 设置页面背景颜色为#f8f8f8
  • 使用flexbox布局将SVG仪表盘和滑块居中显示。
  • 设置进度文本和滑块的样式。

3. 绘制SVG色块

<script>标签中,使用JavaScript动态生成20个色块:

javascript 复制代码
const totalBlocks = 20; // 色块总数
const radius = 120; // 圆的半径
const centerX = 160; // 圆心X坐标
const centerY = 160; // 圆心Y坐标
const blockWidth = 24; // 色块宽度
const blockHeight = 32; // 色块高度
const blockOpacity = 0.3; // 初始透明度
const blockColor = "#ff5722"; // 色块颜色

const blocksGroup = document.getElementById('blocks'); // 获取色块组

// 生成色块
for (let i = 0; i < totalBlocks; i++) {
  const angle = (i / totalBlocks) * 2 * Math.PI - Math.PI / 2; // 计算每个色块的角度
  const x = centerX + radius * Math.cos(angle) - blockWidth / 2; // 计算色块的X坐标
  const y = centerY + radius * Math.sin(angle) - blockHeight / 2; // 计算色块的Y坐标
  const rotate = (angle * 180 / Math.PI) + 90; // 计算旋转角度

  const rect = document.createElementNS("http://www.w3.org/2000/svg", "rect"); // 创建SVG矩形元素
  rect.setAttribute("x", x);
  rect.setAttribute("y", y);
  rect.setAttribute("width", blockWidth);
  rect.setAttribute("height", blockHeight);
  rect.setAttribute("rx", 8); // 设置圆角
  rect.setAttribute("fill", blockColor);
  rect.setAttribute("opacity", blockOpacity);
  rect.setAttribute("transform", `rotate(${rotate} ${x + blockWidth/2} ${y + blockHeight/2})`); // 设置旋转
  rect.setAttribute("id", `block${i}`); // 设置ID
  blocksGroup.appendChild(rect); // 将色块添加到SVG中
}

4. 动态更新进度

<script>标签中,添加以下JavaScript代码来控制进度:

javascript 复制代码
// 控制进度
function setProgress(val) {
  for (let i = 0; i < totalBlocks; i++) {
    const rect = document.getElementById(`block${i}`); // 获取每个色块
    rect.setAttribute("opacity", i < val ? 1 : blockOpacity); // 根据进度值改变透明度
  }
  document.getElementById('progressText').textContent = Math.round(val / totalBlocks * 100) + "%"; // 更新进度文本
  document.getElementById('progressNum').textContent = val; // 更新进度值
}

// 监听滑块
document.getElementById('progressSlider').addEventListener('input', function() {
  setProgress(Number(this.value)); // 根据滑块值更新进度
});

// 初始化
setProgress(0); // 初始进度为0

5. 完整代码

将上述代码整合到一个HTML文件中,完整的代码如下:

xml 复制代码
<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8">
  <title>SVG 带刻度的仪表盘</title>
  <style>
    body {
      background: #f8f8f8;
      display: flex;
      flex-direction: column;
      align-items: center;
      font-family: Arial, sans-serif;
    }
    .gauge-container {
      margin-top: 40px;
      margin-bottom: 20px;
    }
    .progress-value {
      font-size: 2em;
      font-weight: bold;
      text-align: center;
      margin-top: -60px;
      color: #333;
      user-select: none;
    }
    .slider-container {
      margin-top: 30px;
      text-align: center;
    }
  </style>
</head>
<body>
  <div class="gauge-container">
    <svg id="gauge" width="320" height="320" viewBox="0 0 320 320">
      <g id="blocks"></g>
      <circle cx="160" cy="160" r="90" fill="#fff"/>
      <text id="progressText" x="160" y="175" text-anchor="middle" font-size="48" fill="#333" font-weight="bold">0%</text>
    </svg>
  </div>
  <div class="slider-container">
    <input type="range" id="progressSlider" min="0" max="20" value="0" />
    <div>进度:<span id="progressNum">0</span>/20</div>
  </div>

  <script>
    const totalBlocks = 20;
    const radius = 120;
    const centerX = 160;
    const centerY = 160;
    const blockWidth = 24;
    const blockHeight = 32;
    const blockOpacity = 0.3;
    const blockColor = "#ff5722";

    const blocksGroup = document.getElementById('blocks');
    // 生成色块
    for (let i = 0; i < totalBlocks; i++) {
      const angle = (i / totalBlocks) * 2 * Math.PI - Math.PI / 2;
      const x = centerX + radius * Math.cos(angle) - blockWidth / 2;
      const y = centerY + radius * Math.sin(angle) - blockHeight / 2;
      const rotate = (angle * 180 / Math.PI) + 90;
      const rect = document.createElementNS("http://www.w3.org/2000/svg", "rect");
      rect.setAttribute("x", x);
      rect.setAttribute("y", y);
      rect.setAttribute("width", blockWidth);
      rect.setAttribute("height", blockHeight);
      rect.setAttribute("rx", 8);
      rect.setAttribute("fill", blockColor);
      rect.setAttribute("opacity", blockOpacity);
      rect.setAttribute("transform", `rotate(${rotate} ${x + blockWidth/2} ${y + blockHeight/2})`);
      rect.setAttribute("id", `block${i}`);
      blocksGroup.appendChild(rect);
    }

    // 控制进度
    function setProgress(val) {
      for (let i = 0; i < totalBlocks; i++) {
        const rect = document.getElementById(`block${i}`);
        rect.setAttribute("opacity", i < val ? 1 : blockOpacity);
      }
      document.getElementById('progressText').textContent = Math.round(val / totalBlocks * 100) + "%";
      document.getElementById('progressNum').textContent = val;
    }

    // 监听滑块
    document.getElementById('progressSlider').addEventListener('input', function() {
      setProgress(Number(this.value));
    });

    // 初始化
    setProgress(0);
  </script>
</body>
</html>

五、总结

通过以上步骤,你可以使用SVG创建一个简单的带刻度的仪表盘。SVG的优势在于其矢量特性,可以无损放大,并且可以通过CSS和JavaScript轻松实现动态效果。希望这个教程对你有所帮助! 以上制作的是一个最简单的一个带刻度的仪表盘,我还录制了一个更加美观的带刻度的仪表盘的视频教程,有兴趣的小伙伴可以点击查看。

相关推荐
用户98402276679188 天前
【React.js】渐变环形进度条
前端·react.js·svg
明远湖之鱼13 天前
opentype.js 使用与文字渲染
前端·svg·字体
wsWmsw15 天前
[译] 浏览器里的 Liquid Glass:利用 CSS 和 SVG 实现折射
前端·css·svg
CodeCraft Studio16 天前
CAD文件处理控件Aspose.CAD教程:在 Python 中将 SVG 转换为 PDF
开发语言·python·pdf·svg·cad·aspose·aspose.cad
红烧code1 个月前
【Rust GUI开发入门】编写一个本地音乐播放器(4. 绘制按钮组件)
rust·gui·svg·slint
吃饺子不吃馅1 个月前
AntV X6图编辑器如何实现切换主题
前端·svg·图形学
吃饺子不吃馅1 个月前
深感一事无成,还是踏踏实实做点东西吧
前端·svg·图形学
吃饺子不吃馅1 个月前
AntV X6 核心插件帮你飞速创建画布
前端·css·svg
吃饺子不吃馅1 个月前
揭秘 X6 核心概念:Graph、Node、Edge 与 View
前端·javascript·svg
吃饺子不吃馅1 个月前
如何让AntV X6 的连线“动”起来:实现流动效果?
前端·css·svg