canvas绘制太阳系
原文地址:http://jeffzhong.space/2017/10/26/solar/
学习canvas有一段时间了,顺便写个小项目练手,该项目用到的知识点包括:
- ES6面向对象
- 基本的三角函数
- canvas部分有:坐标变换,渐变,混合模式,线条和图形的绘制。
实际效果: solar system(推荐在chrome或safari下运行)
场景
首先建立场景类,主要用来组织管理对象,统一更新和绘制对象。这里用到了ES6的类语法,构造函数建立对象列表属性planets,绘制背景方法drawBG,使用requestAnimationFrame反复执行的动画方法animate
绘制背景使用到了径向渐变:createRadialGradient(x1,y1,r1,x2,y2,r2); 该渐变主要用于创建两个圆相交过渡效果,如果前后两个圆心相同(x1==x2 && y1==y2),则会构造同心圆样式的渐变。 这样我们就以太阳为中心的黄色调渐变到黑色,最后用fillRect填充整个背景。
//场景class Stage {constructor(){this.planets=[];}init(ctx){ctx.translate(W/2,H/2);//坐标重置为中间this.animate(ctx);}//绘制背景drawBG(ctx){ctx.save();ctx.globalCompositeOperation = "source-over";var gradient=ctx.createRadialGradient(0,0,0,0,0,600);gradient.addColorStop(0,'rgba(3,12,13,0.1)');gradient.addColorStop(1,'rgba(0,0,0,1');ctx.fillStyle=gradient;// ctx.fillStyle='rgba(0,0,0,0.9)';ctx.fillRect(-W/2,-H/2,W,H);ctx.restore();}//执行动画animate(ctx){var that=this,startTime=new Date();(function run(){that.drawBG(ctx);that.planets.forEach(item=>{item.update(startTime);item.draw(ctx);});requestAnimationFrame(run);}());}}
星球
然后建立星球基类,除构造函数,还有更新位置角度的方法Update,对象绘制方法draw。之后所有的星球,都会初始化该类或者继承该类建立对应星球。
行星绕太阳做圆周运动,这个可以用三角函数根据角度和半径求出x,y,但还有更加方便的方法,那就是使用canvas提供的坐标旋转方法rotate,以360度为一个周期。
/*** 星球基类*/class Planet{/*** @param {Number} x x坐标* @param {Number} y y坐标* @param {Number} r 半径* @param {Number} duration 周期(秒)* @param {Object} fillStyle * @param {Object} blurStyle */constructor(x,y,r,duration,fillStyle,blurStyle){this.x=x;this.y=y;this.r=r;this.duration=duration;this.angle=0;this.fillStyle=fillStyle;this.blurStyle=blurStyle;}update(startTime){this.angle=Tween.linear(new Date()-startTime,0,Math.PI*2,this.duration*1000);}draw(ctx){ctx.save();ctx.rotate(this.angle);// ctx.translate(this.x,this.y);drawCircle(this.x,this.blurStyle.color);ctx.beginPath();// ctx.globalCompositeOperation = "lighter";ctx.fillStyle=this.fillStyle;ctx.shadowColor=this.blurStyle.color;ctx.shadowBlur=this.blurStyle.blur; // ctx.arc(0,0,this.r,Math.PI*2,false);ctx.arc(this.x,this.y,this.r,0,Math.PI*2,false);ctx.fill();ctx.restore();}};
太阳
开始建立第一个对象-太阳,继承上面的星球基类Planet,重写draw方法
/*** 太阳*/class Sun extends Planet{draw(ctx){ctx.save();ctx.beginPath();ctx.globalCompositeOperation = "source-over";ctx.fillStyle=this.fillStyle;ctx.shadowColor=this.blurStyle.color;ctx.shadowBlur=this.blurStyle.blur; ctx.arc(this.x,this.y,this.r,0,Math.PI*2,false);ctx.fill();ctx.restore(); }}
土星
土星有美丽的土星环,所以也继承出一个单独的类,重写draw方法,其中土星环比较麻烦,建立了很多颜色节点的径向渐变。
/*** 土星*/class Saturn extends Planet{draw(ctx){ctx.save();ctx.rotate(this.angle);drawCircle(this.x,this.blurStyle.color);ctx.beginPath();ctx.fillStyle=this.fillStyle; ctx.arc(this.x,this.y,this.r,Math.PI*2,false);ctx.fill();//土星光环ctx.globalCompositeOperation = "source-over";var gradient=ctx.createRadialGradient(this.x,this.y,0,this.x,this.y,this.r 25);var startStop=(this.r 3)/(this.r 24);gradient.addColorStop(startStop,'#282421');gradient.addColorStop(startStop 0.06,'#282421');gradient.addColorStop(startStop 0.1,'#7e7966');gradient.addColorStop(startStop 0.18,'#706756');gradient.addColorStop(startStop 0.24,'#7e7966');gradient.addColorStop(startStop 0.25,'#282421');gradient.addColorStop(startStop 0.26,'#282421');gradient.addColorStop(startStop 0.27,'#807766');gradient.addColorStop(1,'#595345');ctx.fillStyle=gradient;ctx.beginPath();ctx.arc(this.x,this.y,this.r 24,0,Math.PI*2,true);ctx.arc(this.x,this.y,this.r 3,0,Math.PI*2,false);ctx.fill();ctx.restore(); }}
建立星球
接着开始初始化星球对象,包括太阳和八大行星,然后所有的星球颜色都使用了径向渐变,这样更加的美观。这里给出太阳,水星,土星的例子,其他的行星如此类推。
// 初始化场景类var stage=new Stage();// sunvar sunStyle=ctx.createRadialGradient(0,0,0,0,0,60);sunStyle.addColorStop(0,'white');sunStyle.addColorStop(0.5,'white');sunStyle.addColorStop(0.8,'#ffca1e');sunStyle.addColorStop(1,'#b4421d');var sun=new Sun(0,0,60,0,sunStyle,{color:'#b4421d',blur:300});stage.planets.push(sun);// mercuryvar mercuryStyle=ctx.createRadialGradient(100,0,0,100,0,9);mercuryStyle.addColorStop(0,'#75705a');mercuryStyle.addColorStop(1,'#464646');var mercury=new Planet(100,0,9,8.77,mercuryStyle,{color:'#464646'});stage.planets.push(mercury);//saturn var saturnStyle=ctx.createRadialGradient(500,0,0,500,0,26);saturnStyle.addColorStop(0,'#f2e558');saturnStyle.addColorStop(1,'#4c4a3b');var saturn =new Saturn(500,0,26,1075.995,saturnStyle,{color:'#4c4a3b'});stage.planets.push(saturn);
小行星带
当然还有火星和木星之间的小行星带,同理继承星球基类,这里用到了图像混合模式globalCompositeOperation,使用xor可以和背景对比度没那么突兀。当然还有其他属性值,比如source-over, lighter等。这里我们随机生成了300个对象,一样填充进场景类的planets属性统一更新绘制。
/*** 小行星*/class Asteroid extends Planet{draw(ctx){ctx.save();ctx.rotate(this.angle);ctx.beginPath();ctx.globalCompositeOperation = "xor";ctx.fillStyle=this.fillStyle; ctx.arc(this.x,this.y,this.r,0,Math.PI*2,false);ctx.fill();ctx.restore(); }}function createAsteroids(){var asteroid=null,x=300,y=0, r=2,rd=300,angle=0, d=283, color='#fff';for(var i=0;i<400;i ){rd=Random(300,320);angle=Random(0,Math.PI*2*1000)/1000;x=Math.round(Math.cos(angle)*rd);y=Math.round(Math.sin(angle)*rd);r=Random(1,3);d=Random(28.3,511);color=getAsteroidColor();// console.log(angle,color);asteroid = new Asteroid(x,y,r,d,color,{color:color,blur:1});stage.planets.push(asteroid);}}
彗星
基本快完成了,但我们除此之外,可以再添加做椭圆运动的彗星,这样更加酷。一样随机生成20个彗星填充进场景类统一更新绘制。
/*** 彗星*/class Comet {constructor(cx,cy,a,b,r,angle,color,duration){this.a=a;this.b=b;this.r=r;this.cx=cx;this.cy=cy;this.x=0;this.y=0;this.color=color;this.angle=angle;this.duration=duration;}update(startTime){var t=Tween.linear(new Date()-startTime,0,Math.PI*2,this.duration*1000);this.x=this.cx this.a*Math.cos(this.angle t);this.y=this.cy this.b*Math.sin(this.angle t);}draw(){ctx.save();ctx.rotate(this.angle);//画运动轨迹ctx.lineWidth=0.5;ctx.strokeStyle='rgba(15,69,116,0.2)';Shape.ellipse(ctx,this.cx,this.cy,this.a,this.b);//画球ctx.beginPath();// ctx.globalCompositeOperation = "lighter";ctx.globalCompositeOperation = "source-atop";ctx.shadowColor=this.color;ctx.shadowBlur=1;ctx.fillStyle=this.color;ctx.arc(this.x,this.y,this.r,0,Math.PI*2,false);ctx.fill();//画尾迹ctx.restore();}}function createComets(){var l=180,a=800,b=300,cx=a-l,cy=0,r=3,duration=30,angle=0,color='#fff',comet = null;for(var i=0;i<20;i ){l=Random(120,350)a=Random(600,1000);b=a/Random(1,3);cx=a-l;r=Random(2,4);angle=Random(0,Math.PI*2*1000)/1000;color=getCometColor();duration=Random(20,100);stage.planets.push(new Comet(cx,cy,a,b,r,angle,color,duration));}}
运动轨迹
最后的细节,就是标识出行星圆周运动的轨道,当然最简单的是按运动半径画个圆。但我们用线性渐变添加好看的尾迹,这样效果更好
function drawCircle(r,color){var hsl=Color.hexToHsl(color);ctx.lineWidth=1;// ctx.strokeStyle='rgba(176,184,203,0.3)';// ctx.arc(0,0,this.x,Math.PI*2,false);// ctx.stroke();var gradient=ctx.createLinearGradient(-r,0,r,0);gradient.addColorStop(0,'hsla(' hsl[0] ',' hsl[1] '%,0%,.3)');gradient.addColorStop(0.6,'hsla(' hsl[0] ',' hsl[1] '%,50%,.9)');gradient.addColorStop(1,'hsla(' hsl[0] ',' hsl[1] '%,80%,1)');ctx.strokeStyle=gradient;// ctx.shadowColor=color;// ctx.shadowBlur=4; ctx.beginPath();ctx.arc(0,0,r,0,Math.PI,true);ctx.stroke();}
最后
所有的部分都已经完成,我们只需要启动场景类即可
createAsteroids();createComets();stage.init(ctx);
更多专业前端知识,请上 【猿2048】www.mk2048.com
canvas绘制太阳系相关推荐
- HTML5 canvas绘制太阳系各行星(包括月球的公转)
HTML5 canvas绘制太阳系 看了好多canvas绘制太阳系行星,他们都忽略了月亮,虽然月亮不是行星,但是绘图少了月亮也就没有挑战性了,今天我就计算了一下月亮的轨迹,然后按照公转的比例画了上 ...
- 通过Canvas绘制一个小型太阳系
绘制一个地球绕太阳转,月球绕地球转的小型太阳系 运行效果如下 代码如下 <!DOCTYPE html> <html><head><meta ...
- canvas绘制的文字如何换行
<html><head><title>canvas绘制的文字如何换行</title><style type="text/css" ...
- HTML5 canvas绘制雪花飘落
Canvas是HTML5新增的组件,它就像一块幕布,可以用JavaScript在上面绘制各种图表.动画等.没有Canvas的年代,绘图只能借助Flash插件实现,页面不得不用JavaScript和Fl ...
- canvas绘制时钟
听了慕课网Sliav Zhou 的课程canvas绘制时钟,记录下来的代码,每句做了注解便于以后学习,原先每次边听别的课边敲码,错误百出,明明原封不动复制的代码,就会出错,还找不到原因,今天可能运气好 ...
- canvas绘制圆形
canvas绘制圆形的思路: 1.创建路径 XXX.beginpath(); 2.创建圆形的路径: 3.关闭路径:XXX.closepath(); 路径不关闭也能绘制出图形 4.设定绘制样式. 创建圆 ...
- java canvas 画图片_[Java教程][HTML5] Canvas绘制简单图片
[Java教程][HTML5] Canvas绘制简单图片 0 2016-05-13 13:00:04 获取Image对象,new出来 定义Image对象的src属性,参数:图片路径 定义Image对象 ...
- html5 canvas绘制圆形进度实例
2019独角兽企业重金招聘Python工程师标准>>> html5 canvas绘制圆形进度实例 <canvas id="test" width=200 h ...
- 【Android 应用开发】Canvas 绘制文字 ( 文字尺寸测量 | 基线绘制 )
文章目录 I . 文字尺寸测量 II . 基线绘制 I . 文字尺寸测量 1 . 精准绘制需求 : Canvas 绘制文字时 , 有时需要精准的控制文字的绘制 , 如绘制到指定的区域 , 居中 , 或 ...
- 小猿圈html5教程之canvas绘制线段方法
HTML5现在是时下较火的编程语言之一,但是对于怎么学习很多朋友都是不了解的,不知道从何处下手,针对以上内容小猿圈web前端讲师每天会分享一个web前端知识,希望对你的前端学习有一定的帮助,今天分享的 ...
最新文章
- LeetCode简单题之最少操作使数组递增
- 常用插值算法介绍(二)
- 【Rational Rose使用笔记】用例图
- 关于经典机器学习算法的一个总结
- java integer_Java之Integer类
- 光驱安装centos7系统过程_centos7可以ping通外网_可以ping通内网其他机器_但是其他机器就是ping不通centos7_太神奇了---linux工作笔记041
- iptables第二部分
- Collectors.toSet()
- Latex 常用代码
- 查看git brach_Excel Go Brach – Excelebrations
- lsd 特征点匹配代码_直线匹配-LSD算法
- 关于五笔字型学习五笔难拆汉字学习总结
- # Python第一节课
- Ansible Playbook 变量与 register 详解
- app直播源代码是如何实现直播间小游戏的
- xuelipay 个人即时到账收款平台 原理及源码详解 支持支付宝微信
- Android绘制饼状图
- 国内高速下载 GitHub 下载单文件夹和 release 的方法
- html布局结构瀑布流,三种方式实现瀑布流布局
- windows系统遇到的问题?