echarts 实现环形渐变
前言
最近产品在ecahrts官网上找到一个 饼图 想要实现这种从头到尾的渐变交互效果,一开始以为非常简单,echarts应该是提供了类似的配置项,知道做起来才发现,这其中没那么简单。
官网案例分析
官网例子中的渐变并不是echarts提供的配置项实现的,而是通过一张 图片 作为背景实现的渐变,所以一开始想着是先来实现一个渐变的饼图,然后通过多个饼图进行拼接来实现类似指针一样的效果,这样就能够实现自定义这个渐变的颜色,并且也很快就写出来一个demo
认识 Echarts 渐变色
在 echarts 的渐变色中,提供了三种类型,包括线性渐变(linear gradient)、径向渐变(radial gradient)和纹理填充(pattern)。
主要了解了一下 线性渐变 以及 径向渐变 的实现效果,在这之后,也意识到了一个严重的问题:通过echarts提供的颜色填充,貌似没办法实现案例里面这种从头到尾的渐变效果,通过线性渐变能够实现下面这种效果
这种固定方向的渐变,但是并不符合我们的要求,
并且我也上网找了一些饼图渐变的案例,发现都是通过这种线性渐变来实现的,只不过会去计算这个渐变的角度,来实现类似从头到尾的渐变,但是一旦进度的幅度较大,就马上露馅了。
- 例子
可以看到一旦我调大某一个区域的比例,就会发现最后的实现原理还是线性渐变,只不过动态的计算了角度,这种适合多个比例差不多的饼图,但是一旦有某个块比例过大,就还是会出现样式不够美观
奇思妙想
突然意识到,我们最终的目的是自定义这个圆环的起点和终点的颜色,这并不是非得用echarts提供的渐变功能,图片本身并没有问题,图片最大的限制就在于颜色是定好的,但是我们是不是可以让图片的颜色变成动态生成的?
当然可以!
与似乎,就有了下面的方案,通过 canvas 动态生成渐变背景,在讲这张背景图作为圆环的背景图,这样我们就能够实现自定义圆环的起点颜色和终点颜色了
canvas 生成渐变背景
canvas生成背景这个并不是什么难事,百度一下就能够找到类似的案例,然后丢给ai进行美化一下,修改参数变成自己想要的一个函数,我定义的是能够通过传入起点角度,起点颜色,终点颜色 图片大小 四个参数生成一张 base64 的图片
/**
* 创建圆形渐变图片
* @param startAngle 起始角度
* @param startColor 起始颜色
* @param endColor 结束颜色
* @param size 大小
* @returns
*/
export function createCircularGradientImage(startAngle = 0, startColor = '#fff', endColor = 'blue', size = 200) {
// 创建一个canvas元素
const canvas = document.createElement('canvas')
// 设置canvas的宽度
canvas.width = size
// 设置canvas的高度
canvas.height = size
// 获取2D绘图上下文
const ctx = canvas.getContext('2d')
// 检查是否成功获取上下文
if (!ctx) {
throw new Error('ctx is null')
}
// 创建圆锥渐变
// 参数:起始角度,圆心x坐标,圆心y坐标
const gradient = ctx.createConicGradient(startAngle, size / 2, size / 2)
// 添加渐变的起始颜色
gradient.addColorStop(0, startColor)
// 添加渐变的结束颜色
gradient.addColorStop(1, endColor)
// 设置填充样式并绘制矩形
ctx.fillStyle = gradient
ctx.fillRect(0, 0, size, size)
// 将canvas转换为base64格式的图片数据
const res = canvas.toDataURL('image/png')
// 从DOM中移除canvas元素
canvas.remove()
// 返回生成的图片数据
return res
}
最终我们能够得到一张类似这样的图片
结果
接下来的步骤就简单了,参考官网的案例,我们只不过是替换了图片的来源,这样就能够通过传参获得一个自定义颜色的结果。
const _panelImageURL = createCircularGradientImage(0, '#E5E5FF', 'red')
最后的效果:
至于文字颜色和阴影颜色,这些都有着很明显的配置项,这里就不做过多的赘述了,本文主要是分享一下通过canvas构造图片来实现渐变的这种思路
如果有大佬有更好的实现渐变的思路欢迎评论区留言!