根据多个点使用canvas贝赛尔曲线画一条平滑的曲线
众所周知想用canvas画一条曲线我们可以使用这些函数:
二次曲线:quadraticCurveTo(cp1x, cp1y, x, y)
贝塞尔曲线:bezierCurveTo(cp1x, cp1y, cp2x, cp2y, x, y)
画圆弧:arcTo(x1,y1,x2,y2,radius);
但是如果一组点给你,怎么通过这些已知点画一条平滑的曲线呢?使用二次曲线,或是圆弧?恐怕这些都没法满足曲线多变的需求,唯一的方法就是一段贝塞尔曲线连着一段贝塞尔曲线。于是乎我在百度上大海捞针,发现居然没有一个人把自己的算法放出来,太不人道了,被逼无奈的我只好从理论入手,先了解一下贝赛尔曲线的控制点计算方法,说起来容易,想要画贝赛尔曲线谁都会,但是计算控制点你就会遇到一点小麻烦,这次我突击恶补了一下终于弄懂了怎么计算贝赛尔曲线控制点的方法。
百度一下贝塞尔曲线控制点计算方法,在搜索结果第一条有一篇百度文库的文章《怎样确定 Bezier 曲线的控制点》,通过浏览全文找到了计算控制点的公式,以下是核心结论。
哎妈,是不是看了之后头都大了,反正公式已经给出来了,就让我们用行数去实现这个Ai和Bi点的计算吧,忘了说一句a、b可以为任意正数,等我们完成了我们的demo可以测试一下不同的a、bz值对我们的曲线会造成什么影响
/*
*根据已知点获取第i个控制点的坐标
*param ps 已知曲线将经过的坐标点
*param i 坐标点的个数
*param a,b 可以自定义的正数
*/
function getCtrlPoint(ps, i, a, b){
if(!a||!b){
a=0.25;
b=0.25;
}
var pAx = ps[i].x + (ps[i+1].x-ps[i-1].x)*a;
var pAy = ps[i].y + (ps[i+1].y-ps[i-1].y)*a;
var pBx = ps[i+1].x - (ps[i+2].x-ps[i].x)*b;
var pBy = ps[i+1].y - (ps[i+2].y-ps[i].y)*b;
return {
pA:{x:pAx,y:pAy},
pB:{x:pBx,y:pBy}
}
}
写完这些心中不免有些疑问,ps是我们的坐标点数组,我们的第0个点和第n-1、n个点怎么办,我函数中的ps[n-1+2]和ps[n+2]是会超数组范围的,于是我接着往文库文章下面看,文中他给我们提供了两种解决办法。
方法2确实麻烦,我比较急迫的想看到效果,于是选择了第一种方案,有兴趣的同学可以在附件中找到这篇文章,自己回去研究研究,在我的算法上进行改进。
于是乎我改进了我的函数。
/*
*根据已知点获取第i个控制点的坐标
*param ps 已知曲线将经过的坐标点
*param i 第i个坐标点
*param a,b 可以自定义的正数
*/
function getCtrlPoint(ps, i, a, b){
if(!a||!b){
a=0.25;
b=0.25;
}
//处理两种极端情形
if(ips.length-3){
var last=ps.length-1
var pBx = ps[last].x - (ps[last].x-ps[last-1].x)*b;
var pBy = ps[last].y - (ps[last].y-ps[last-1].y)*b;
}else{
var pBx = ps[i+1].x - (ps[i+2].x-ps[i].x)*b;
var pBy = ps[i+1].y - (ps[i+2].y-ps[i].y)*b;
}
return {
pA:{x:pAx,y:pAy},
pB:{x:pBx,y:pBy}
}
}
nice!接下来开始我们的canvas画图工作吧。
一、首先顶一个点数组,将我们即将描绘的坐标点模拟出来。
var point=[{x:0,y:380},{x:100,y:430},{x:200,y:280},{x:300,y:160},
{x:400,y:340},{x:500,y:100},{x:600,y:300},{x:700,y:240}]
二、开始遍历我们的坐标数组这里为了方便描述point简称p,下标point[n]简称pn。
1)创建一个画布,将画笔的移动到p0点,这是我们的起始点。
2)循环点数组,在循环体中使用我们定义的getCtrlPoint函数计算出第i个点A、B两个控制点的点坐标。
var ctrlP=getCtrlPoint(point,i-1);
ctx.bezierCurveTo(ctrlP.pA.x, ctrlP.pA.y, ctrlP.pB.x,ctrlP.pB.y, point[i].x, point[i].y);
3)刷新页面看效果吧
是不是很有感觉?为了再次确认我话的曲线是否有问题,我又画了一些辅助线,标出了控制点,并且直线连接各个点与我们的贝塞尔曲线做个对比。于是得到了下图。
红色是通过点与控制点的连线,绿色是控制点与控制点之间的连线,蓝色的是直线连接各点画的线。
可以看到所有的点一个不落的被贝赛尔曲线贯穿,达到了我们希望的效果,通过这次探索,以后什么曲线都不怕了,明天再研究研究怎么把这条实线改成虚线,这些都是HighCharts、ECharts直流的基础,有了这个demo曲线图表什么的再也不怕了,想想心里还有些小激动呢。
最后奉上本次成果的demo:demo.rar
还有前面提到的百度文库的文章:贝塞尔曲线控制点确定的方法.doc
来自:根据多个点使用canvas贝赛尔曲线画一条平滑的曲线
根据多个点使用canvas贝赛尔曲线画一条平滑的曲线的更多相关文章
- canvas之画一条线段
var canvas=document.getElementById("canvas"); //设置绘图环境 var cxt=canvas.getContext('2d'); // ...
- 使用JavaScript在Canvas上画出一片星空
随着Html5的迅猛发展,画布也变得越来越重要.下面我就写一个关于在canvas上画出一片星空的简单的代码的示例. 理论基础 初始化一个canvas,获得一个用于绘制图形的上下文环境context.并 ...
- Canvas中如何画一条清晰的线宽为奇数(如1px逻辑像素)的线?
我在开发中使用canvas的机会不是很多,但是第一次实际使用中就遇到了问题,"很久很久以前,我自己画了一个雷达图,线宽都是1像素,但是显示效果不如期望,这才发现canvas中的画线还是有坑的 ...
- (转)第02节:在Canvas上画简单的图形
我们现在已经可以在HTML中使用Fabric.js库了,那这节我们就详细的学习一下如何在canvas上画出简单的图形. 在画东西之前我们需要了解画任何东西的基本三个步骤: 声明画布(canvas),用 ...
- Canvas 如何画一个四分之一圆
转: Canvas 如何画一个四分之一圆 HTML: Document JS: var c = document.getElementById('ctx') var ctx = c.getContex ...
- canvas绘制圆形进度条(或显示当前已浏览网页百分比)
使用canvas绘制圆形进度条,或者是网页加载进度条 或者是显示你浏览了本网页多少-- 由于个浏览器的计算差异,打开浏览器时 初始值有所不同,但是当拉倒网页底部时,均显示100%. 兼容性:测试浏览器 ...
- html5 canvas绘制环形进度条,环形渐变色仪表图
html5 canvas绘制环形进度条,环形渐变色仪表图 在绘制圆环前,我们需要知道canvas arc() 方 ...
- Canvas实现环形进度条
Canvas实现环形进度条 直接上代码: <canvas width="200" height="200" >60%</canvas> ...
- 平面上画n条直线,最多能将平面分成多少部分?
转自:http://blog.csdn.net/cywosp/article/details/6724522 在一个平面上画1999条直线,最多能将这一平面划分成多少个部分? 没有直线时有一个空间:( ...
随机推荐
- Java并发编程之final域的内存语义
一.final域的重排序规则 对于final域,编译器和处理器要遵循两个重拍序规则: 1.在构造函数内对一个final域的写入,与随后把这个被构造对象的引用赋值给一个引用变量,这两个操作之间不能重排序 ...
- 七:MyBatis学习总结(七)——Mybatis缓存
---恢复内容开始--- 一.MyBatis缓存介绍 正如大多数持久层框架一样,MyBatis 同样提供了一级缓存和二级缓存的支持 一级缓存: 基于PerpetualCache 的 HashMap本地 ...
- centos7修改默认运行级别的变化
在学习centos7,视频教学中使用的的centos6,查看权限文件命令为 cat /etc/inittab/ 但是在centos7中输入以下命令会出现这种情况 这个已经不用了,现在修改权限的命令修改 ...
- day 68crm(5) 分页器的进一步优化,以及在stark上使用分页器,,以及,整理代码,以及stark组件search查询
前情提要: 本节内容 自定制分页器 保存及查询记录 代码整理, stark组件search 查询 一:自定制分页器 page 1:创建类 Pagination # 自定制分页器 _ _init ...
- OpenCV2计算机编程手册(二)基于类的图像处理
1. 在算法设计中使用策略(Strategy)模式 策略设计模式的目标是将算法封装在类中.因此,可以更容易地替换一个现有的算法,或者组合使用多个算法以拥有更复杂的处理逻辑.此外,该模式将算法的复杂度隐 ...
- 【9】JMicro微服务-发布订阅消息服务
如非授权,禁止用于商业用途,转载请注明出处作者:mynewworldyyl 1. JMicro消息服务目前实现特性 a. JMicro只支持发布订阅消息服务,不支持队列式消息服务: b. 不支持消息持 ...
- 使用findbugs为自己的代码review
转自:http://blog.lichengwu.cn/java/2013/11/24/use-findbugs-code-review/ 介绍 Findbugs是一个代码静态分析工具,用来找出Jav ...
- 2、如何解决xamarin没有相关教程的的指导贴
本篇文章主要在于解决xamarin相关文档偏少的问题. 最终的代码并不重要.重要的还是那种处理的方式 授人以渔 群里有群友讨论说需要读取安卓的 充电电流.这样的问题实际上在原生java有一堆.但是到了 ...
- 由一段代码谈前端js优化和编码规范(一) 分类: JavaScript 2015-03-21 12:43 668人阅读 评论(1) 收藏
这段代码是撸主刚毕业那会写的,主要是实现一个左侧的导航条的折叠功能.当时实现的比较简陋,每次在导航条增加新的项目的时候,都要手动去修改js代码中写死的索引...确实是比较恼火的,后来就修改了一下,能够 ...
- notepad++上搭建gtk+2.0/3.x开发环境
前言 老师布置了一道题需要用到图形界面,于是开始找图形库.最后选择了gtk+图形库,然后折腾了大概一天. 这里记录自己新学到的知识,同时也给后来者一些便利. 准备 下载以下内容 notepad++(由 ...