文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

基于canvas如何使用贝塞尔曲线平滑拟合折线段

2023-06-09 14:52

关注

小编给大家分享一下基于canvas如何使用贝塞尔曲线平滑拟合折线段,希望大家阅读完这篇文章之后都有所收获,下面让我们一起去探讨吧!

为什么要平滑拟合折线段

先来看下Echarts下折线图的渲染效果:

基于canvas如何使用贝塞尔曲线平滑拟合折线段 

一开始我没注意到其实这个折线段是曲线穿过去的,只认为是单纯的描点绘图,所以起初我实现的“简(丑)易(陋)”版本是这样的:

基于canvas如何使用贝塞尔曲线平滑拟合折线段

不要关注样式,重点就是实现之后才发现看起来人家Echarts的实现描点非常的圆滑,也由此引发了之后的探讨。怎么有规律的画平滑曲线?

效果图

先来看下最终模仿的实现:

因为我也不知道Echarts内部怎么实现的(逃

基于canvas如何使用贝塞尔曲线平滑拟合折线段 

基于canvas如何使用贝塞尔曲线平滑拟合折线段 

看起来已经非常圆润了,和我们最初的设想十分接近了。再看下曲线是否穿过了描点:

基于canvas如何使用贝塞尔曲线平滑拟合折线段 

好的!结果很明显现在来重新看下我们的实现方式。

实现过程

  1. 绘制折线图

  2. 贝塞尔曲线平滑拟合

模拟数据

var data = [Math.random() * 300];        for (var i = 1; i < 50; i++) { //按照echarts            data.push(Math.round((Math.random() - 0.5) * 20 + data[i - 1]));        }        option = {            canvas:{                id: 'canvas'            },            series: {                name: '模拟数据',                itemStyle: {                    color: 'rgb(255, 70, 131)'                },                areaStyle: {                    color: 'rgb(255, 158, 68)'                },                data: data            }        };

绘制折线图

首先初始化一个构造函数来放置需要用到的数据:

function LinearGradient(option) {    this.canvas = document.getElementById(option.canvas.id)    this.ctx = this.canvas.getContext('2d')    this.width = this.canvas.width    this.height = this.canvas.height    this.tooltip = option.tooltip    this.title = option.text    this.series = option.series //存放模拟数据}

绘制折线图:

LinearGradient.prototype.draw1 = function() { //折线参考线    ...     //要考虑到canvas中的原点是左上角,    //所以下面要做一些换算,    //diff为x,y轴被数据最大值和最小值的取值范围所平分的等份。    this.series.data.forEach(function(item, index) {        var x = diffX * index,            y = Math.floor(self.height - diffY * (item - dataMin))        self.ctx.lineTo(x, y) //绘制各个数据点    })    ...}

贝塞尔曲线平滑拟合

贝塞尔曲线的关键点在于控制点的选择,这个网站可以动态的展现控制点不同而绘制的不同的曲线。而对于控制点的计算。。作者还是选择了百度一下毕竟数学不好:)。具体算法有兴趣的同学可以深入了解下,现在直接说下计算控制点的结论。

基于canvas如何使用贝塞尔曲线平滑拟合折线段

上面的公式涉及到四个坐标点,当前点,前一个点以及后两个点,而当坐标值为下图展示的时候绘制出来的曲线如下所示:

基于canvas如何使用贝塞尔曲线平滑拟合折线段

不过会有一个问题就是起始点和最后一个点不能用这个公式,不过那篇文章也给出了边界值的处理办法:

基于canvas如何使用贝塞尔曲线平滑拟合折线段 

所以在将折线换成平滑曲线的时候,将边界值以及其他控制点计算好之后代入到贝塞尔函数中就完成了:

//核心实现this.series.data.forEach(function(item, index) { //找到前一个点到下一个点中间的控制点    var scale = 0.1 //分别对于ab控制点的一个正数,可以分别自行调整    var last1X = diffX * (index - 1),        last1Y = Math.floor(self.height - diffY * (self.series.data[index - 1] - dataMin)),        //前一个点坐标        last2X = diffX * (index - 2),        last2Y = Math.floor(self.height - diffY * (self.series.data[index - 2] - dataMin)),        //前两个点坐标        nowX = diffX * (index),        nowY = Math.floor(self.height - diffY * (self.series.data[index] - dataMin)),        //当期点坐标        nextX = diffX * (index + 1),        nextY = Math.floor(self.height - diffY * (self.series.data[index + 1] - dataMin)),        //下一个点坐标        cAx = last1X + (nowX - last2X) * scale,        cAy = last1Y + (nowY - last2Y) * scale,        cBx = nowX - (nextX - last1X) * scale,        cBy = nowY - (nextY - last1Y) * scale     if(index === 0) {        self.ctx.lineTo(nowX, nowY)        return    } else if(index ===1) {        cAx = last1X + (nowX - 0) * scale        cAy = last1Y + (nowY - self.height) * scale     } else if(index === self.series.data.length - 1) {        cBx = nowX - (nowX - last1X) * scale        cBy = nowY - (nowY - last1Y) * scale    }         self.ctx.bezierCurveTo(cAx, cAy, cBx, cBy, nowX, nowY);        //绘制出上一个点到当前点的贝塞尔曲线    })

由于我每次遍历的点都是当前点,但是文章中给出的公式是计算会知道下一个点的控制点算法,故在代码实现中我将所有点的计算挪前了一位。当index = 0时也就是初始点是不需要曲线绘制的,因为我们绘制的是从前一个点到当前点的曲线,没有到0的曲线需要绘制。从index = 1开始我们就可以正常开始绘制,从0到1的曲线,由于index = 1时是没有在他前面第二个点的故其属于边界值点,也就是需要特殊进行计算,以及最后一个点。其余均按照正常公式算出AB的xy坐标代入贝塞尔函数即可。

看完了这篇文章,相信你对“基于canvas如何使用贝塞尔曲线平滑拟合折线段”有了一定的了解,如果想了解更多相关知识,欢迎关注编程网行业资讯频道,感谢各位的阅读!

阅读原文内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     807人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     351人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     314人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     433人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     221人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-后端开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯