canvas && CSS 两种实现仪表盘的方式

栏目: Html5 · 发布时间: 5年前

内容简介:先上效果图:这种图形大家应该都见过,俗称仪表盘,当然,上图只是个最基本的仪表盘架子,可能在实际场景中还会其他很多花里胡哨的点缀,那些暂且不管,不是关键,这东西经常见到,但还没亲自上手在代码层面实现过,最近做的一个需求恰好有这个场景,这里归纳一下大部分情况下,对于这种偏可视化的元素,一般都选择使用

先上效果图:

canvas && CSS 两种实现仪表盘的方式

这种图形大家应该都见过,俗称仪表盘,当然,上图只是个最基本的仪表盘架子,可能在实际场景中还会其他很多花里胡哨的点缀,那些暂且不管,不是关键,这东西经常见到,但还没亲自上手在代码层面实现过,最近做的一个需求恰好有这个场景,这里归纳一下

canvas实现

大部分情况下,对于这种偏可视化的元素,一般都选择使用 canvas 来进行绘制,现在已经 9120 年了,线上使用 canvas 完全没问题

仪表盘整体是一个复杂图形,而复杂图形是由简单图形组合而成,只要把所有组成这个仪表盘的简单图形绘制出来,再进行组合,整个仪表盘自然也就绘制出来了

所以,首先对仪表盘进行分解,分解成 canvas 能绘制出的基本图形,其主体其实就两个圆弧,一个是底部蓝色的半圆轨道,一个是代表进度的红色圆弧,其实都是圆弧, canvas 刚好有绘制圆弧的能力,即:

ctx.arc
复制代码

至于动态绘制,只需要配合 requestAnimationFrame 即可

const trackW = 6
const rx = 500
const ry = 500
const radius = 400
const innerLineW = 20
const canvas = document.getElementById('canvas')
const ctx = canvas.getContext('2d')
function draw (toAngle, currentAngle = Math.PI) {
  ctx.clearRect(0, 0, canvas.width, canvas.height)
  // 半圆轨道
  ctx.beginPath()
  ctx.strokeStyle = '#ad80fc'
  ctx.lineWidth = trackW
  ctx.arc(rx, ry, radius, Math.PI, 0, false)
  ctx.stroke()
  // 圆弧
  ctx.beginPath()
  ctx.lineCap = 'round'
  ctx.strokeStyle = '#fe4d55'
  ctx.lineWidth = innerLineW
  ctx.arc(rx, ry, radius, Math.PI, currentAngle, false)
  ctx.stroke()
  if (currentAngle < toAngle) {
    currentAngle += 0.02
    if (currentAngle > toAngle) currentAngle = toAngle
    requestAnimationFrame(() => {
      draw(toAngle, currentAngle)
    })
  }
}
draw(1.5 * Math.PI)
复制代码

加上变量定义,花括号等几十行代码即可完成,由此可见, canvas 绘图还是很方便的,所以在可视化领域,例如一些库或者 UI 组件基本上都是以 canvas 进行构建

css绘制

canvas 实质上就是借助 js 操纵浏览器 API 进行渲染,然而 UI 渲染这种事情本应该交给 CSS 来做才是,感觉用 js 直接画多影响性能啊(实际上并不),哪有 css 来的流畅,实际上, css 完全可以做到

css 的角度对仪表盘进行分解,同样还是两个圆弧,通过设置 border-radius 属性即可让元素呈现整圆效果,然后再用一个矩形元素进行遮罩,决定展现出来的部分,即为圆弧,通过控制遮罩的面积来呈现动态绘制的效果

<div class="arc-wrapper">
  <p class="track-arc"></p>
  <div class="round-box">
    <p class="round"></p>
  </div>
</div>
复制代码
:root {
  --arcRadius: 200px;
  --rectWidth: calc(var(--arcRadius) * 2);
  --trackWidth: 4px;
  --roundWidth: 10px;
}
.arc-wrapper {
  position: relative;
  margin: 0 auto;
  width: var(--rectWidth);
  height: var(--arcRadius);
  overflow: hidden;
  background-color: pink;
}
.track-arc {
  width: 100%;
  height: var(--rectWidth);
  box-sizing: border-box;
  border-radius: 50%;
  border: var(--trackWidth) solid #ad80fc;
}
.round-box {
  position: absolute;
  left: 0;
  top: 0;
  width: 100%;
  height: 100%;
  overflow: hidden;
  transform-origin: 50% 100%;
  transform: rotate(-45deg);
  z-index: 20;
}
.round {
  width: 100%;
  height: var(--rectWidth);
  box-sizing: border-box;
  border-radius: 50%;
  border: var(--roundWidth) solid #fe4d55;
}
复制代码

其实没多少代码,也没什么难以理解的,只不过效果似乎微调:

canvas && CSS 两种实现仪表盘的方式

由于圆弧的线是存在宽度的,并不是数学意义上的可以忽略, canvas 绘制圆弧,是根据圆心坐标和半径进行绘制的,绘制出来的圆弧会自动根据圆弧 line 的宽度进行调整,即圆弧的半径是圆弧线的中心位置与圆心坐标距离

canvas && CSS 两种实现仪表盘的方式

而通过 css 绘制的圆弧,此圆弧的半径则是圆弧最外层边线与圆心的坐标距离:

canvas && CSS 两种实现仪表盘的方式

知道了问题其实就好解决了,只要缩减轨道半圆的半径,并对其进行一定的偏移即可:

.track-arc {
  --trackArcSize: calc(var(--rectWidth) - var(--roundWidth) + var(--trackWidth));
  /* 尺寸改变 */
  width: var(--trackArcSize);
  height: var(--trackArcSize);
  box-sizing: border-box;
  border-radius: 50%;
  border: var(--trackWidth) solid #ad80fc;
  /* 位置偏移 */
  transform: translate(calc(var(--roundWidth) / 2 - var(--trackWidth) / 2), calc(var(--roundWidth) / 2 - var(--trackWidth) / 2));
}
复制代码

然后就顺眼多了:

canvas && CSS 两种实现仪表盘的方式

然而,还有个问题,一般为了呈现更加圆润的效果,设计稿上圆弧的断点处一般都是圆头:

canvas && CSS 两种实现仪表盘的方式

而上述呈现出来的效果是直接截断的:

canvas && CSS 两种实现仪表盘的方式

一般人之所以不使用 css 来绘制仪表盘,基本都是因为这个原因, canvas 简简单单通过设置一个 ctx.lineCap = 'round' 就能解决的问题。似乎 css 无解了

乍一看好像确实没什么好办法,但稍微思考下,这不就是一个圆角吗,完全在 css 能力范围内啊,只不过实现的方式不太那么直接罢了

方法很简单,就是使用一个圆角矩形覆盖在圆弧的顶端,将圆弧本身的矩形顶端覆盖住,圆角矩形当做是圆弧的顶端,这样视觉上看起来不就是圆头了吗

<div class="round-box">
  <p class="round"></p>
  <p class="dot-r-box">
    <span class="dot-r"></span>
  </p>
</div>
复制代码
.dot-r-box {
  position: absolute;
  right: 0;
  bottom: 0;
  width: var(--roundWidth);
  height: var(--dotHeight);
  background-color: var(--backColor);
}
.dot-r {
  display: inline-block;
  width: 100%;
  height: 100%;
  /* 这里的100px只是为了呈现出最大限度的圆角 */
  border-bottom-left-radius: 100px;
  border-bottom-right-radius: 100px;
  background-color: var(--roundColor);
}
复制代码

效果如下:

canvas && CSS 两种实现仪表盘的方式

圆角顶端 get

同样的,圆弧左边的顶端也可以这么做

canvas && CSS 两种实现仪表盘的方式

不过左边这个顶端有个稍微需要注意的地方,因为其存在的目的是为了当做圆弧的左断点,但是当进度为 0 的时候,圆弧应该是完全不展现的,或者当进度很小的时候,圆弧应该展现的长度还没有 dot-l 的高度大,这样就露馅了:

canvas && CSS 两种实现仪表盘的方式

不过呢转而又一想,一般实际场景中,就算进度为 0 ,我们其实为了看起来更符合常识直觉,也会让圆弧展现一点点出来,只要 dot-l 的高度不是太大,或者说只要圆弧的宽度不要太宽,其实预留的这点圆弧完全就可以 cover 住了,不至于露馅


以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

内容创业:内容、分发、赢利新模式

内容创业:内容、分发、赢利新模式

张贵泉、张洵瑒 / 电子工业出版社 / 2018-6 / 49

越来越多的内容平台、行业巨头、资本纷纷加入内容分发的战争中,竞争非常激烈。优质的原创性内容将成为行业中最宝贵的资源。在这样的行业形势下,如何把内容创业做好?如何提高自身竞争力?如何在这场战争中武装自己?是每一位内容创业者都应该认真考虑的问题。 《内容创业:内容、分发、赢利新模式》旨在帮助内容创业者解决这些问题,为想要进入内容行业的创业者出谋划策,手把手教大家如何更好地进行内容创业,获得更高的......一起来看看 《内容创业:内容、分发、赢利新模式》 这本书的介绍吧!

SHA 加密
SHA 加密

SHA 加密工具

XML、JSON 在线转换
XML、JSON 在线转换

在线XML、JSON转换工具

RGB CMYK 转换工具
RGB CMYK 转换工具

RGB CMYK 互转工具