canvas绘制自定义的曲线,以椭圆为例,通俗易懂,童叟无欺
本篇文章,将讲述如何通过自定义的曲线函数,使用canvas的方式进行曲线的绘制。
为了通俗易懂,将以大家熟悉的椭圆曲线为例,进行椭圆的绘制。至于其他比较复杂的曲线,用户只需通过数学方式建立起曲线函数,然后变换成为距离函数方程,替换即可。另外:代码还没进行任何优化。
(注:本文只适合那种能在一个点为原点、基于原点的每个角度只能存在一个点的曲线,通俗说就是,过原点作直线,与曲线相交的交点最多两个,而且两交点分别位于原点两端。)
目录结构
正文:
1、数学分析
首先讲解下椭圆的构造,如图所示,数学厉害的忽视这段。
======================================分割线,数学帝请忽略这一段==================================
椭圆构造图
其中,OA,OB分别为半长轴和短长轴,通过此两线段的距离能计算出半焦距FO的长度,再确定心O的坐标就能确认整个椭圆的范围。
由此可知,清楚了OA,OB的距离,就能知道椭圆的形状。
百度百科里面讲到,
椭圆的标准方程有两种,取决于焦点所在的坐标轴:
1)焦点在X轴时,标准方程为:x²/a²+y²/b²=1 (a>b>0)
2)焦点在Y轴时,标准方程为:y²/a²+x²/b²=1 (a>b>0)
其实两个概念差不多一样,将a 和 b在方程中的位置对调就行。不详细讲。
看好,我要变形了。→_→
假设θ为∠POF,P点距离x轴的长度为Y1的值,设为y;距离Y轴长度为X1值,设为X,P点基于O的坐标就是(x1,y1)。
tanθ = y/x
y = xtanθ
带入椭圆方程 x²/a²+x2(tanθ)2/b²=1,解得(注:tanθ*tanθ,不记得是用tanθ2/tan2θ表示了,貌似是tan2θ,本文统一(tanθ)2表示)
x2 = a2b2 / (b2+a2(tanθ)2),带入y = xtanθ,并进行化简得出 x2+y2 = (a2b2(1+(tanθ)2)/ (b2+a2(tanθ)2),就是说,通过a,b,θ 能计算出OP 的距离来了。
======================================分割线,忽略了上面段的可以回来了====================================
2、曲线方程
因此,得到一个方程,返回的是OP的距离
/*
func:
ellipseFunc:return the length
args:
a:[number] ellipse's a
b:[number] ellipse's b
theta:[number] how much of Math.PI
*/
function ellipseFunc(a,b,theta) {
// javascript Math对象下面的三角函数,传入的theta值必须是转换成弧度制的值,就是多少个3.141592…等等等的那个弧度制
return Math.pow(((a*a*b*b)*(1+Math.tan(theta)*Math.tan(theta)))/(b*b+a*a*Math.tan(theta)*Math.tan(theta)),1/2);
}
3、画一个点
既然曲线函数完毕,下面就行画图了,先从画一个点来说,网上很对关于描绘一个点的帖子,我选了ctx.fillRect(x,y,a,b),这是绘制矩形的函数,x、y为绘制矩形的起点,就是左上角,设置a=b=1,就能绘制一个长宽各为1px大小的矩阵,个人喜欢使用其他也行。
下面是绘制一个点的函数,填充风格没有定义,在传入_ctx时是什么fillStyle就填充什么风格。
/*
func:
drawPoint:draw a point
args:
_ctx:[object]the canvas's getContent("2d") variable
point:[object] the point where to draw a dot such as {"x":200,"y":200}
strokwidth:[number] the draw line's width and height
*/
function drawPoint(_ctx,point,strokwidth){
strokwidth = strokwidth || 1;
if(!(_ctx !== undefined && _ctx !== null)) return false;
var x = point.x,
y = point.y;
_ctx.fillRect(x,y,strokwidth,strokwidth);
return true;
}
4、画形状
点的绘制讲述完毕,开始画曲线了,用for循环,画图吧。
/*
func:
drawShape:draw a shape
args:
canvasId:[string]the canvas's id
func:[function]the shape function
ellipse:[object] the ellipse's a and b length such as {"a":300,"b":200}
center:[object] the draw center such as {"x":400,"y":400}
*/
function drawShape(canvasId,func,ellipse,center){
var _c = document.getElementById(canvasId);
if(_c === null) return false;
var _ctx = _c.getContext("2d");
// 默认椭圆中心为canvas的中心
var a = ellipse.a || 0,
b = ellipse.b || 0,
centerX = center.x || _c.width/2,
centerY = center.y || _c.height/2,
drawX,drawY,pointCX,pointCY;
shapeGet = func;
for(var i = 0;i <= 2*Math.PI; i+=0.0001){// 通过弧度绘图,精确到每个0.0001弧度画图,可以更加精确。但是小图的话,没必要那么精确,浪费CPU时间。
length = shapeGet(a,b,i);
pointCX = length*Math.cos(i);
pointCY = length*Math.sin(i);
drawX = centerX + pointCX;
drawY = centerY - pointCY;
drawPoint(_ctx,{"x":drawX,"y":drawY},1);
}
return true;
}
调用方式
drawShape("myCanvas",ellipseFunc,{"a":300,"b":200},{"x":400,"y":400});
页面的全部源码如下:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
</head>
<body>
<div id="cloud">
<canvas id="myCanvas" width="800" height="800"></canvas>
</div> <script>
/*
func:
ellipseFunc:return the length
args:
a:[number] ellipse's a
b:[number] ellipse's b
theta:[number] how much of Math.PI
*/
function ellipseFunc(a,b,theta) {
// javascript Math对象下面的三角函数,传入的theta值必须是转换成弧度制的值,就是多少个3.141592…等等等的那个弧度制
return Math.pow(((a*a*b*b)*(1+Math.tan(theta)*Math.tan(theta)))/(b*b+a*a*Math.tan(theta)*Math.tan(theta)),1/2);
} /*
func:
drawPoint:draw a point
args:
_ctx:[object]the canvas's getContent("2d") variable
point:[object] the point where to draw a dot such as {"x":200,"y":200}
strokwidth:[number] the draw line's width and height
*/
function drawPoint(_ctx,point,strokwidth){
strokwidth = strokwidth || 1;
if(!(_ctx !== undefined && _ctx !== null)) return false;
var x = point.x,
y = point.y;
_ctx.fillRect(x,y,strokwidth,strokwidth);
return true;
} /*
func:
drawShape:draw a shape
args:
canvasId:[string]the canvas's id
func:[function]the shape function
ellipse:[object] the ellipse's a and b length such as {"a":300,"b":200}
center:[object] the draw center such as {"x":400,"y":400}
*/
function drawShape(canvasId,func,ellipse,center){
var _c = document.getElementById(canvasId);
if(_c === null) return false;
var _ctx = _c.getContext("2d");
// 默认椭圆中心为canvas的中心
var a = ellipse.a || 0,
b = ellipse.b || 0,
centerX = center.x || _c.width/2,
centerY = center.y || _c.height/2,
drawX,drawY,pointCX,pointCY;
shapeGet = func;
for(var i = 0;i <= 2*Math.PI; i+=0.0001){// 通过弧度绘图,精确到每个0.0001弧度画图,可以更加精确,0.0001更加欢迎。但是小图的话,没必要那么精确,浪费CPU时间。
length = shapeGet(a,b,i);
pointCX = length*Math.cos(i);
pointCY = length*Math.sin(i);
drawX = centerX + pointCX;
drawY = centerY - pointCY;
drawPoint(_ctx,{"x":drawX,"y":drawY},1);
}
return true;
}
drawShape("myCanvas",ellipseFunc,{"a":300,"b":200},{"x":400,"y":400}); </script>
</body>
</html>
5、废话
本文产生的原因,本来是想做词云的,给定词云的形状,在这个形状内填充词语,产生了这个念头,词云还没实现,关键是如何才能让填充词语相互不覆盖的问题。后来,选择在github里面搜索算了,选择了一个jQuery.awesomeCloud.plugin,但是填充效率确实压力山大。想过去模拟他的方法,做一个出来,因此先从画自定义曲线开始了。
canvas绘制自定义的曲线,以椭圆为例,通俗易懂,童叟无欺的更多相关文章
- Android绘图机制(二)——自定义View绘制形, 圆形, 三角形, 扇形, 椭圆, 曲线,文字和图片的坐标讲解
Android绘图机制(二)--自定义View绘制形, 圆形, 三角形, 扇形, 椭圆, 曲线,文字和图片的坐标讲解 我们要想画好一些炫酷的View,首先我们得知道怎么去画一些基础的图案,比如矩形,圆 ...
- 如何使用canvas绘制椭圆,扩展非chrome浏览器中的ellipse方法
这篇博文主要针对浏览器中绘制椭圆的方法扩展.在网上搜索了很多,发现他们绘制椭圆的方式都有缺陷.其中有压缩法,计算法,贝塞尔曲线法等多种方式.但是都不能很好的绘制出椭圆.所有我就对这个绘制椭圆的方式进行 ...
- canvas绘制贝塞尔曲线
原文:canvas绘制贝塞尔曲线 1.绘制二次方贝塞尔曲线 quadraticCurveTo(cp1x,cp1y,x,y); 其中参数cp1x和cp1y是控制点的坐标,x和y是终点坐标 数学公式表示如 ...
- canvas绘制曲线
canvas绘制曲线 方法 quadraticCurveTo(cp1x, cp1y, x, y) 只有一个控制点的贝塞尔曲线(其实就是控制点分别与起始点和结束点连线的公切线) bezierCurveT ...
- Android自定义组件系列【9】——Canvas绘制折线图
有时候我们在项目中会遇到使用折线图等图形,Android的开源项目中为我们提供了很多插件,但是很多时候我们需要根据具体项目自定义这些图表,这一篇文章我们一起来看看如何在Android中使用Canvas ...
- 基于canvas二次贝塞尔曲线绘制鲜花
canvas中二次贝塞尔曲线参数说明: cp1x:控制点1横坐标 cp1y:控制点1纵坐标 x: 结束点1横坐标 y:结束点1纵坐标 cp2x:控制点2横坐标 cp2y:控制点2纵坐标 z:结束点2横 ...
- 【朝花夕拾】Android自定义View篇之(三)Canvas绘制文字
前言 转载请声明,转自[https://www.cnblogs.com/andy-songwei/p/10968358.html],谢谢! 前面的文章中在介绍Canvas的时候,提到过后续单独讲Can ...
- 一次js自定义播放器,canvas绘制弹幕的尝试
不多bb,就直接说实现了什么功能: 1. 视频播放进度调整 2. 视频小窗口实时预览 3. 声音调整 4. 画中画模式 5. 网页全屏 6. 视频全屏 7. canvas绘制弹幕 8. 选中弹幕悬停 ...
- Canvas绘制图形
1.Canvas绘制一个蓝色的矩形 <!DOCTYPE html> <html> <head lang="en"> <meta chars ...
随机推荐
- RESTful架构详解(转)
1. 什么是REST REST全称是Representational State Transfer,中文意思是表述(编者注:通常译为表征)性状态转移. 它首次出现在2000年Roy Fielding的 ...
- Spring : 征服数据库 (两)
本节介绍Spring和ORM集成框架.尽管Hibernate在开源ORM 社区很受欢迎.但是,本文将MyBatis案例解说.也MyBatis和Hibernate好坏是没有意义的,主要看实际需求,有兴趣 ...
- Windows命令行命令集锦
原文:Windows命令行命令集锦 转自:http://www.me2wg.com/bbs/forum.php?mod=viewthread&tid=15830 winver--------- ...
- 配置SQL Server 2008的资源调控器实现负载均衡
原文:配置SQL Server 2008的资源调控器实现负载均衡 转自:http://www.ithov.com/server/93267.shtml 1.为什么引入"资源调控器" ...
- Ajax实践之用户是否存在
关于Ajax在之前的学习中,已经对它的基础知识有了初步的了解.仅仅是欠实践. 那么接下来就让实践来检验一下真理吧! 基础见:http://blog.csdn.net/liu_yujie2011com/ ...
- Ubuntu 15.10 x64 安装 Android SDK(转)
操作系统:Ubuntu 15.10 x64 目标:安装 Android SDK 本文最后更新时间:2015-11-3 安装32位库文件 2013年9月的iPhone 5s是第一款64位手机,而Andr ...
- .net安装包自动安装Mysql数据库
原文:.net安装包自动安装Mysql数据库 在制作.Net安装包的时候,如果项目有用到数据库,怎么能够把数据库打包安装呢?网上已经有很多自动安装Sql Server数据库的例子,但是自动安装mysq ...
- 第三十讲:Android之Animation(五)
天行健,君子以自强不息.--<周易·乾·象> 本讲内容:逐帧动画 Frame Animation 逐帧动画 Frame Animation就是说一帧一帧的连起来播放就变成了动画,和放电影的 ...
- 《Java并发编程实战》第十四章 构建自己的同步工具定义 札记
一.状态依赖性的管理 有界缓存实现的基类 @ ThreadSafe public abstract class BaseBoundedBuffer<E> { @GuardeBy( &quo ...
- hdu 4911 Inversion(找到的倒数)
主题链接:http://acm.hdu.edu.cn/showproblem.php?pid=4911 Inversion Time Limit: 2000/1000 MS (Java/Others) ...