SVG数据可视化组件基础教程4:连续进度的仪表盘

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

一、目标

通过SVG和JavaScript实现一个渐变色圆形仪表盘,具有以下特点:

  1. 使用线性渐变色来显示进度。
  2. 动态更新进度,展示从0到80的下载速度值。
  3. 包含刻度数字,显示不同的速度值。
  4. 使用滑块控制进度值。

二、所需工具与准备

  1. 工具

    • 一个文本编辑器(如Notepad++、VS Code等)。
    • 浏览器(用于预览效果)。
  2. 基础准备

    • 确保你对HTML、CSS和JavaScript有一定的了解。
    • 确保你对SVG的基本语法有一定了解。

三、代码分析与操作步骤

1. 创建HTML结构

创建一个HTML文件(如Lesson4.html)并设置基本的HTML结构:

xml 复制代码
<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8">
  <title>SVG 渐变仪表盘</title>
  <style>
    /* 样式部分 */
  </style>
</head>
<body>
  <div class="gauge-container">
    <svg id="gauge" width="350" height="300" viewBox="0 0 350 300">
      <!-- SVG内容 -->
    </svg>
  </div>
  <div class="slider-container">
    <input type="range" id="progressSlider" min="0" max="80" value="0" step="1" style="width:300px;" />
    <div>进度:<span id="progressNum">0</span> / 80</div>
  </div>

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

2. 添加CSS样式

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

css 复制代码
body {
  background: #fff;
  display: flex;
  flex-direction: column;
  align-items: center;
  font-family: Arial, sans-serif;
}
.gauge-container {
  margin-top: 40px;
  margin-bottom: 20px;
}
.slider-container {
  margin-top: 30px;
  text-align: center;
}
  • 设置页面背景颜色为白色。
  • 使用flexbox布局将SVG仪表盘和滑块居中显示。
  • 设置滑块容器的样式。

3. 定义SVG渐变

<svg>标签中,定义一个线性渐变:

ini 复制代码
<defs>
  <linearGradient id="gaugeGradient" x1="0%" y1="0%" x2="100%" y2="0%">
    <stop offset="0%" stop-color="#2563eb"/>
    <stop offset="100%" stop-color="#60a5fa"/>
  </linearGradient>
</defs>
  • gaugeGradient:定义了一个从#2563eb#60a5fa的线性渐变。

4. 绘制背景和进度圆弧

<svg>标签中,添加背景和进度圆弧的路径元素:

ini 复制代码
<path
  id="gauge-bg"
  d=""
  stroke="#e5e7eb"
  stroke-width="18"
  fill="none"
  stroke-linecap="round"
/>
<path
  id="gauge-progress"
  d=""
  stroke="url(#gaugeGradient)"
  stroke-width="18"
  fill="none"
  stroke-linecap="round"
/>
  • gauge-bg:背景圆弧,颜色为浅灰色。
  • gauge-progress:进度圆弧,使用定义的渐变色。

5. 添加刻度数字和中心元素

<svg>标签中,添加刻度数字和中心元素:

arduino 复制代码
<g id="gauge-labels"></g>
<circle cx="175" cy="175" r="90" fill="white" opacity="0.95"/>
<text x="175" y="130" text-anchor="middle" font-size="18" fill="#888" font-weight="bold">Download</text>
<text id="gauge-value" x="175" y="170" text-anchor="middle" font-size="44" fill="#222" font-weight="bold">0</text>
<text x="175" y="200" text-anchor="middle" font-size="18" fill="#888" font-weight="bold">Mbps</text>
  • gauge-labels:用于显示刻度数字。
  • 中心白色圆和文字:用于显示进度值。

6. 编写JavaScript代码

<script>标签中,添加以下JavaScript代码来实现动态效果:

ini 复制代码
const minValue = 0;
const maxValue = 80;
const startAngle = 225;
const endAngle = 495;
const radius = 120;
const centerX = 175;
const centerY = 175;

// 极坐标转笛卡尔
function polarToCartesian(cx, cy, r, angle) {
  const rad = (angle-90) * Math.PI / 180.0;
  return {
    x: cx + (r * Math.cos(rad)),
    y: cy + (r * Math.sin(rad))
  };
}

// 生成圆弧路径
function describeArc(cx, cy, r, startAngle, endAngle) {
  const start = polarToCartesian(cx, cy, r, endAngle);
  const end = polarToCartesian(cx, cy, r, startAngle);
  const largeArcFlag = endAngle - startAngle <= 180 ? "0" : "1";
  return [
    "M", start.x, start.y,
    "A", r, r, 0, largeArcFlag, 0, end.x, end.y
  ].join(" ");
}

// 绘制背景圆弧
function drawGaugeBg() {
  const bgPath = document.getElementById('gauge-bg');
  bgPath.setAttribute("d", describeArc(centerX, centerY, radius, startAngle, endAngle));
}

// 绘制进度圆弧
function drawGaugeProgress(value) {
  const progressPath = document.getElementById('gauge-progress');
  const percent = (value - minValue) / (maxValue - minValue);
  const angle = startAngle + percent * (endAngle - startAngle);
  if (value === 0) {
    progressPath.setAttribute("d", "");
  } else {
    progressPath.setAttribute("d", describeArc(centerX, centerY, radius, startAngle, angle));
  }
}

// 绘制刻度数字
function drawGaugeLabels() {
  const labelsGroup = document.getElementById('gauge-labels');
  labelsGroup.innerHTML = '';
  const numLabels = 8;
  for (let i = 0; i <= numLabels; i++) {
    const percent = i / numLabels;
    const angle = startAngle + percent * (endAngle - startAngle);
    const pos = polarToCartesian(centerX, centerY, radius + 28, angle);
    const label = document.createElementNS("http://www.w3.org/2000/svg", "text");
    label.setAttribute("x", pos.x);
    label.setAttribute("y", pos.y + 6);
    label.setAttribute("text-anchor", "middle");
    label.setAttribute("font-size", "16");
    label.setAttribute("fill", "#7ca0d9");
    label.setAttribute("font-weight", "bold");
    label.textContent = Math.round(minValue + percent * (maxValue - minValue));
    labelsGroup.appendChild(label);
  }
}

// 控制进度
function setProgress(val) {
  drawGaugeProgress(val);
  document.getElementById('gauge-value').textContent = val;
  document.getElementById('progressNum').textContent = val;
}

// 初始化
drawGaugeBg();
drawGaugeLabels();
setProgress(0);

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

7. 完整代码

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

ini 复制代码
<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8">
  <title>SVG 渐变仪表盘</title>
  <style>
    body {
      background: #fff;
      display: flex;
      flex-direction: column;
      align-items: center;
      font-family: Arial, sans-serif;
    }
    .gauge-container {
      margin-top: 40px;
      margin-bottom: 20px;
    }
    .slider-container {
      margin-top: 30px;
      text-align: center;
    }
  </style>
</head>
<body>
  <div class="gauge-container">
    <svg id="gauge" width="350" height="300" viewBox="0 0 350 300">
      <defs>
        <linearGradient id="gaugeGradient" x1="0%" y1="0%" x2="100%" y2="0%">
          <stop offset="0%" stop-color="#2563eb"/>
          <stop offset="100%" stop-color="#60a5fa"/>
        </linearGradient>
      </defs>
      <path
        id="gauge-bg"
        d=""
        stroke="#e5e7eb"
        stroke-width="18"
        fill="none"
        stroke-linecap="round"
      />
      <path
        id="gauge-progress"
        d=""
        stroke="url(#gaugeGradient)"
        stroke-width="18"
        fill="none"
        stroke-linecap="round"
      />
      <g id="gauge-labels"></g>
      <circle cx="175" cy="175" r="90" fill="white" opacity="0.95"/>
      <text x="175" y="130" text-anchor="middle" font-size="18" fill="#888" font-weight="bold">Download</text>
      <text id="gauge-value" x="175" y="170" text-anchor="middle" font-size="44" fill="#222" font-weight="bold">0</text>
      <text x="175" y="200" text-anchor="middle" font-size="18" fill="#888" font-weight="bold">Mbps</text>
    </svg>
  </div>
  <div class="slider-container">
    <input type="range" id="progressSlider" min="0" max="80" value="0" step="1" style="width:300px;" />
    <div>进度:<span id="progressNum">0</span> / 80</div>
  </div>

  <script>
    const minValue = 0;
    const maxValue = 80;
    const startAngle = 225;
    const endAngle = 495;
    const radius = 120;
    const centerX = 175;
    const centerY = 175;

    // 极坐标转笛卡尔
    function polarToCartesian(cx, cy, r, angle) {
      const rad = (angle-90) * Math.PI / 180.0;
      return {
        x: cx + (r * Math.cos(rad)),
        y: cy + (r * Math.sin(rad))
      };
    }

    // 生成圆弧路径
    function describeArc(cx, cy, r, startAngle, endAngle) {
      const start = polarToCartesian(cx, cy, r, endAngle);
      const end = polarToCartesian(cx, cy, r, startAngle);
      const largeArcFlag = endAngle - startAngle <= 180 ? "0" : "1";
      return [
        "M", start.x, start.y,
        "A", r, r, 0, largeArcFlag, 0, end.x, end.y
      ].join(" ");
    }

    // 绘制背景圆弧
    function drawGaugeBg() {
      const bgPath = document.getElementById('gauge-bg');
      bgPath.setAttribute("d", describeArc(centerX, centerY, radius, startAngle, endAngle));
    }

    // 绘制进度圆弧
    function drawGaugeProgress(value) {
      const progressPath = document.getElementById('gauge-progress');
      const percent = (value - minValue) / (maxValue - minValue);
      const angle = startAngle + percent * (endAngle - startAngle);
      if (value === 0) {
        progressPath.setAttribute("d", "");
      } else {
        progressPath.setAttribute("d", describeArc(centerX, centerY, radius, startAngle, angle));
      }
    }

    // 绘制刻度数字
    function drawGaugeLabels() {
      const labelsGroup = document.getElementById('gauge-labels');
      labelsGroup.innerHTML = '';
      const numLabels = 8;
      for (let i = 0; i <= numLabels; i++) {
        const percent = i / numLabels;
        const angle = startAngle + percent * (endAngle - startAngle);
        const pos = polarToCartesian(centerX, centerY, radius + 28, angle);
        const label = document.createElementNS("http://www.w3.org/2000/svg", "text");
        label.setAttribute("x", pos.x);
        label.setAttribute("y", pos.y + 6);
        label.setAttribute("text-anchor", "middle");
        label.setAttribute("font-size", "16");
        label.setAttribute("fill", "#7ca0d9");
        label.setAttribute("font-weight", "bold");
        label.textContent = Math.round(minValue + percent * (maxValue - minValue));
        labelsGroup.appendChild(label);
      }
    }

    // 控制进度
    function setProgress(val) {
      drawGaugeProgress(val);
      document.getElementById('gauge-value').textContent = val;
      document.getElementById('progressNum').textContent = val;
    }

    // 初始化
    drawGaugeBg();
    drawGaugeLabels();
    setProgress(0);

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

四、总结

通过以上步骤,你可以创建一个精美的SVG渐变仪表盘。这个仪表盘具有渐变色背景、动态进度圆弧、刻度数字和滑块控制功能。你可以通过调整代码中的参数来改变仪表盘的外观和行为。希望这个教程对你有所帮助! 以上制作的是一个最简单的一个带刻度的仪表盘,我还录制了一个更加美观的带刻度的仪表盘的视频教程,有兴趣的小伙伴可以点击查看。

相关推荐
Python当打之年4 小时前
【62 Pandas+Pyecharts | 智联招聘大数据岗位数据分析可视化】
大数据·python·数据分析·pandas·数据可视化
勇太的数分之旅8 小时前
Excel大厂自动化报表实战(互联网金融-数据分析周报制作上)
金融·数据分析·自动化·excel·数据可视化
勇太的数分之旅8 小时前
Excel大厂自动化报表实战(互联网金融-数据分析周报制作中)
金融·数据分析·自动化·excel·数据可视化
木鱼时刻11 小时前
低代码可配置化统计分析平台架构设计
低代码·数据可视化
设计师也学前端11 小时前
SVG数据可视化组件基础教程5:带指针连续进度的仪表盘
svg·数据可视化
CodeDevMaster1 天前
Python数据可视化:Seaborn入门与实践
python·数据可视化
微笑边缘的金元宝1 天前
svg实现3环进度图,可动态调节进度数值,(vue)
前端·javascript·vue.js·svg
设计师也学前端2 天前
SVG数据可视化组件基础教程:带刻度的仪表盘
svg
设计师也学前端3 天前
SVG数据可视化组件基础教程:带指针的仪表盘
svg