乐趣区

关于前端:图表开发小案例快来码一个性感妖娆的高逼格-圆环

日常生产生存中,咱们会常常读到或应用各种类型的图表。圆环(圆弧)便是一种较常见的类型,用于直观展示某一数据指标占整体的比例。本文以 HTML Canvas 的实现为主(当然,SVG 党能够在理解原理后自行实现),逐层介绍圆环图表开发的一些次要思路和原理。

图 1 所示是一些咱们平时比拟常见的一些圆环(圆弧)成果。尽管图形的主体形成都是圆弧,但不同成果在信息传播的性能上却略有差别。如:

  • 闭合的圆环能够示意流程“进度”的概念
  • 非闭合圆环个别用于状态量(标量)的展现,个别也称为“仪表盘”成果
  • 不同的色相可用于标识状态量的状态区间(如:低危 - 中危 - 高危 区间的标识能够应用三种色彩的形成的过渡成果进行表白)

为了更加不便、欠缺地解决咱们在业务开发时的具体须要,能够对这些格调、款式进行肯定剖析、形象,总结出一个通用组件须要具备的能力,如:

  • 色彩、突变可配(反对传入繁多色值或色彩序列)
  • 圆弧宽度可调(内、外半径大小可配置)
  • 圆弧夹角可调(开始角度、截止角度可配置)
  • 圆弧端点造型可选(可切换平角 / 半圆造型
  • 文案成果可调(字号、字体、色彩等)

上面,咱们着手于实现这样一个性能全面、业务通用性较强的圆环组件。

1. 圆环的造型

绘制圆环造型的第一步,须要先绘制圆环图表形成因素,即一段一段的圆弧。而对于像下图中这样的两种倒角成果(黄色局部圆弧两端的款式),既能够是直角,也能够是半圆。

因而,咱们须要实现一个通用的办法来绘制圆弧,提供两种倒角格调给用户。

1.1 前景圆弧的绘制

圆弧绘制的思路如上图所示,按先后顺序大抵分为几个步骤:

(1)绘制圆弧起始端的半圆轮廓(2)绘制圆弧的外边缘轮廓(3)绘制圆弧终止端的半圆轮廓(4)绘制圆弧的内边缘轮廓(5)闭合轮廓并填充色调 

注:因为 canvas 绘制圆弧的办法默认是顺时针方向,因此咱们的绘图步骤也是沿着顺时针方向

以下是一些姿态要领:

1.1.1 端点坐标的计算

在绘制端点半圆之前咱们须要端点的地位坐标,以其实端为例,依据圆环的半径(内外径的均值,即圆弧中线的半径)和起始端点的角度如何计算圆上一点的坐标:

// 计算圆弧上某点的坐标
// originX, originY - 圆心的坐标
// radius - 圆环半径,等于圆环内、外径的平均值,也即圆弧中线的半径
// alpha - 弧度
function calcPosition(originX, originY, radius, alpha) {
  return [radius * Math.cos(alpha) + originX,
    radius * Math.sin(alpha) + originY,
  ];
}

1.1.2 端点半圆的起止角度

在 canvas 中绘制一个 arc,须要晓得其起始角度和终止角度。因为 canvas 绘制默认方向为屏幕顺时针方向(屏幕 Z 轴 的左手螺旋方向),从下面的示意图中能够看出:

 起始端半圆弧度范畴 - [radianStart - Math.PI, radianStart]
终止端半圆弧度范畴 - [radianEnd, radianEnd + Math.PI]

1.1.3 绘制半圆

有了端点坐标和起止角度,便能够绘制端点的半圆:

// 以起始端的半圆倒角为例
myCanvas.context.arc(
  x,
  y,
  (radiusOutter - radiusInner) / 2,     // 小圆半径,等于圆环线宽的一半
  radianStart - Math.PI,
  radianStart
);

直角倒角格调的绘制与半圆倒角圆弧的绘制步骤基本相同,次要差异在于不必绘制圆弧两个端点的小半圆,改成绘制直线。背景圆弧的绘制也与前景圆弧办法统一。

2. Canvas 实现锥形突变

下面的步骤能够绘制出圆弧的轮廓,要达到 图 1 那样的视觉效果,咱们须要给后面绘制进去的轮廓填充图像。

沿着圆周方向的突变,因为其图像形似圆锥体的鸟瞰成果,俗称锥形突变:

家喻户晓,CSS 中有一个名为 conic-gradient 的属性间接反对锥形突变,而 HTML Canvas 的原生 API 目前还没有相似的能力。那么,咱们如何在 canvas 中绘制出这样的图像呢?

上面咱们讲下大抵的原理:

(1)对用户传入的色彩进行插值,失去一个色彩序列。

这里,咱们间接应用 canvas 原生的 createLinearGradient 办法,在离屏 canvas 中绘制一个 1px 的线性突变成果,图像宽度正好是咱们要插值的数量,突变插值的后果也就是 canvas 上对应像素地位的色值。

色彩插值(突变取色)代码实现如下:

// 用于实现色彩插值的工具类
export default class ColorInterpolate {// 参数 01: stops - 为要插值的色彩序列,数据格式形如:[[0, 'red'], [0.5, 'green'], [1.0, 'yellow']]
  // 参数 02: segment - 插值段落数,即插值后果的色彩值的数量
  constructor(stops = [], segment = 100) {
    // 构建离屏 canvas
    const canvas = document.createElement('canvas');
    canvas.width = segment;
    canvas.height = 1;
    this.ctx = canvas.getContext('2d');

    // 绘制线性突变
    const gradient = this.ctx.createLinearGradient(0, 0, segment, 0);
    for (let [offset, color] of stops) {gradient.addColorStop(offset, color);
    }

    this.ctx.fillStyle = gradient;
    this.ctx.fillRect(0, 0, segment, 1);
  }

  // 依据地位偏移量获取插值后的色值
  getColor(offset) {const imgData = this.ctx.getImageData(offset, 0, 1, 1);
    return `rgba(${imgData.data.slice(0, 3).join(',')}, ${imgData.data[3] / 255})`;
  }
}

(2)如下图所示,咱们能够把突变的图像看成是由足够多填充了单个色值的小“扇面”拼接而成。

依照这样的思路,咱们只须要遍历下面色调插值失去的各个色彩,而后一一绘制小扇面,便可失去一个锥形突变图像。

为此咱们封装了一个名为 createConicalGradient 的办法,其应用习惯与 canvas 原生的 createLinearGradient 和 createRadialGradient 办法类似。具体代码见 我的 Github(感觉有用的童鞋能够 star 一下)。

3. 过渡动画

3.1 圆弧的过渡

在数值产生扭转时,咱们的图表须要一个可能追随数据扭转的过渡动画成果,对于 canvas 而言,便是革除旧图像而后绘制新一帧图像。这里有一些办法包装上的技巧:

// 注:伪代码,实在场景倡议 OOP 形式包装为工具类

let _animTick = null;
let _animFrames = null;
let _frameData = null;
let _animDiff = null;

// 动画办法
function _animate(duration) {if (_animTick === null) {
    // 依据动画时长 duration 计算整个动画一共须要多少帧(以 60fps 计算)_animFrames = Math.round((duration / 1e3) * 60);

    // 相邻两帧动画的数据变动
    _animDiff = _calcAnimDiff(_animFrames);

    // 动画帧数标识
    _animTick = 0;
  }

  // 以后帧的数据值
  _frameData = _caclCurentData(_animDiff, _animTick);
  _renderFrame(_frameData);

  if (_animTick !== null && _animTick < _animFrames) {
    // 继续执行动画
    window.requestAnimationFrame(() => {_animate();
      _animTick += 1;
    });
  } else {
    // 动画完结
    _renderFrame(_frameData);
    _animTick = null;
  }
}

// 绘制以后帧
function _renderFrame(data) {// ...}

// 计算动画相邻帧的数据差别
function _calcAnimDiff() {// ...}

// 依据两帧数据差计算以后帧
function _caclCurentData() {// ...}

3.2 两种动画模式

在过渡动画执行的过程中,须要思考两种不同的模式:一种是突变图像不变动,仅是圆弧的轮廓从旧状态变动到新状态;一种是突变图像的夹角范畴追随轮廓的大小扭转。

这两种模式其实都有肯定意义:前者能够应用不同色彩代表数值的不同状态;后者仅仅是将突变的色彩看成一种装璜成果。

4. 后果演示

比拟要害的原理都介绍完了,最初展现一下咱们封装的图表组件的成果(右侧 GUI 局部是咱们自研的设计引擎的编辑成果):

5. 写在前面

本文是可视化图表开发的一个小案例,也是【图表开发小案例】这个系列的第一篇。篇幅比拟短,还有很多细节没有展开讨论。感兴趣的童鞋欢送交换、探讨,请多多关注咱们前面的推文 ~(^_^)Y

退出移动版