又到了樱花的季节,教大家使用canvas画出飞舞的樱花树效果。

废话少说,先看效果。

演示效果地址:http://suohb.com/work/tree4.htm

查看演示效果

第一步,我们先画出一棵树的主体。

我画树的使用的原理是,定义一个起始点,从这个点开始,向一个角度移动一段距离。得到另一个点。

画出一条线连接两个点。

以新得到的点,依旧向这个角度,移动一段距离。得到第三个点,连写第二第三个点。

以此类推。一定步长之后,就得到一条射线。

我们根据自然界中的真实树的情况,这条线越来越细,直到最细地方结束。

<body bgcolor="#000000">
<canvas id="tree"></canvas>
<script>
var treeCanvas = document.getElementById("tree");
treeCanvas.width = window.innerWidth;
treeCanvas.height = window.innerHeight ;
var tCxt = treeCanvas.getContext("2d");
var rootTop = 450 ;//树起始位置
var treeColor = "#FFF" ;//树颜色 function drawTree(x,y,deg,step){
var x1 = x + Math.cos(deg) * step ;//越细的枝干越短,所以以步长来做
var y1 = y + Math.sin(deg) * step ;
tCxt.beginPath();
tCxt.lineWidth = step/3;//树干越来越细
tCxt.moveTo(x,y);
tCxt.lineTo(x1,y1);
tCxt.strokeStyle = treeColor ;
tCxt.stroke();
step -- ;
if(step > 0){
drawTree(x1,y1,deg,step);
}
} drawTree(treeCanvas.width/2,rootTop,-Math.PI/2,30);
</script>
</body>

树干出来之后,要做分叉,每个分叉其实就是向另一个方向的树干。

而且分叉要比主干细一些。我们在第二阶段树干位置,每三步向左右分叉。

if(step > 0){
drawTree(x1,y1,deg,step);
if(step%3 == 1)
drawTree(x1,y1,deg+0.5 ,Math.round(step/1.13));//右分叉
if(step%3 == 0)
drawTree(x1,y1,deg-0.5, Math.round(step/1.13));//左分叉
}

这样一棵树的主干基本上就已经完成了。

我们在树的末端几个节点,画一个粉色的半透明的圆。当做樱花。

为了保证所有樱花不是千篇一律的一个角度,我们随机一个起始角度。

function drawTree(x,y,deg,step){
var x1 = x + Math.cos(deg) * step ;//越细的枝干越短,所以以步长来做
var y1 = y + Math.sin(deg) * step ;
tCxt.beginPath();
tCxt.lineWidth = step/3;//树干越来越细
tCxt.moveTo(x,y);
tCxt.lineTo(x1,y1);
tCxt.strokeStyle = treeColor ;
tCxt.stroke();
if(step < 5 ){//在末端五个节点,画一个半圆,作为樱花效果
var r = 2+Math.random()*2
tCxt.fillStyle = flowerColor ;
tCxt.arc(x1+Math.random()*3,y1+Math.random()*3,r,0,Math.PI)
tCxt.fill();
}
step -- ;
if(step > 0){
drawTree(x1,y1,deg,step);
if(step%3 == 1)
drawTree(x1,y1,deg+0.5 ,Math.round(step/1.13));//右分叉
if(step%3 == 0)
drawTree(x1,y1,deg-0.5, Math.round(step/1.13));//左分叉
}
}

这个时候,如果没有特别的要求的,基本算是已经完成了。

之后再要做的就是精益求精,对现在效果做出微调。

1、树干都是直线,在计算下一个点的时候,做一些偏移。

2、樱花树形态比较扁平。给X轴方向上偏移稍微大点,Y轴稍微偏小一点。

3、至少做两种花瓣颜色,一种稍微深一些,一种浅一些。

4、在新建一个canvas层,做一些飘落樱花的效果。

5、在分叉,画花瓣等地方多使用一些随机数,树形状不能太单一

最终效果如下:

完整代码如下:

<!doctype html>
<html>
<head>
<meta http-equiv="Pragma" content="no-cache" />
<meta http-equiv="Cache-Control" content="no-cache" />
<meta http-equiv="Expires" content="0" />
<meta http-equiv="Content-Type" content="text/html;charset=utf-8" />
<meta name="viewport" content="width=device-width,initial-scale=1.0,user-scalable=no" />
<style type="text/css">
canvas{
position: absolute;
left: 0;
top: 0;
}
</style>
</head>
<body bgcolor="#000000">
<canvas id="tree"></canvas>
<canvas id="flower"></canvas>
<script>
//两个canvas
var tree = document.getElementById("tree");
tree.width = window.innerWidth;
tree.height = window.innerHeight ;
var tCxt = tree.getContext("2d");
var flower = document.getElementById("flower");
flower.width = window.innerWidth;
flower.height = window.innerHeight ;
var cxt = flower.getContext("2d"); var flowerList = [];//樱花列表
var rootTop = 450 ;//树起点
var flowerColor = "rgba(255,192,203,.3)" ;//花色
var flowerColorDeep = "rgba(241,158,194,.5)" ;//花色深
var treeColor2 = "rgba(255,192,203,.5)" ;//树枝颜色
var treeColor = "#FFF" ;//树干颜色
var fallList = [];//飘落樱花列表
var g = 0.01 ;//重力加速度
var gWind = 0.005;//风力加速度
var limitSpeedY = 1;//速度上限
var limitSpeedX = 1 ;//速度上限 cxt.shadowColor= "#FFF" ;
cxt.shadowBlur = 10 ; function drawTree(x,y,deg,step,type){
var deg1 = step%2 == 0 ? 0.1 : -0.1 ;
var x1 = x + Math.cos(deg+deg1) * (step+4) * 0.8 ;//以步长来判断枝干长度 x轴偏移大一些
var y1 = y + Math.sin(deg+deg1) * (step-1) * 0.8 ;//以步长来判断枝干长度 Y轴压缩一些
tCxt.beginPath();
tCxt.lineWidth = step/3;
tCxt.moveTo(x,y);
tCxt.lineTo(x1,y1);
tCxt.strokeStyle = (step > 5 ) ? treeColor : treeColor2 ;//细纸条都换成花的颜色
tCxt.stroke();
if(step > 20){//树干相交的位置有间隙,以一个圆填充
tCxt.fillStyle = treeColor ;
tCxt.arc(x,y,step/6,0,Math.PI*2);
tCxt.fill();
}
if(step < 3 || (step < 23 && Math.random() > 0.1)){
//末梢位置 画花瓣
var color = [flowerColorDeep,flowerColor,flowerColor][Math.round(Math.random()+0.2)] ;
var r = 2+Math.random()*2
tCxt.fillStyle = color ;
tCxt.arc(x1+Math.random()*3,y1+Math.random()*3,r,0,Math.PI)
tCxt.fill();
flowerList.push({x:x,y:y,sx:(Math.random()-0.5),sy:0,color:color,r:r,deg:deg});//保存下画樱花的位置
}
step -- ;
if(step > 0){
drawTree(x1,y1,deg,step,type);
if(step%3 == 1 && step > 0 && step < 30)
drawTree(x1,y1,deg+0.2 + 0.3 * Math.random(),Math.round(step/1.13));//右分叉
if(step%3 == 0 && step > 0 && step < 30)
drawTree(x1,y1,deg-0.2 - 0.3 * Math.random(),Math.round(step/1.13));//左分叉
}
} drawTree(tree.width/2,rootTop,-Math.PI/2,30,1);//执行 var len = flowerList.length ;
function step(){
if(Math.random() > 0.3) fallList.push(flowerList[Math.floor(Math.random()*len)]);//随机取出一个,花瓣复制到飘落花瓣的列表中 cxt.clearRect(0,0,tree.width,tree.height);
for(var i = 0 ;i < fallList.length ; i ++){
if(fallList[i].sy < limitSpeedY) fallList[i].sy += g ;
fallList[i].sx += gWind ;
fallList[i].x += fallList[i].sx ;
fallList[i].y += fallList[i].sy ;
if(fallList[i].y > rootTop){//飘到树根的花瓣移除
fallList.splice(i,1);
i -- ;
continue ;
}
cxt.beginPath();
cxt.fillStyle = fallList[i].color ;
fallList[i].deg += fallList[i].sx*0.05 ;//跟速度相关的旋转花瓣
cxt.arc(fallList[i].x,fallList[i].y,fallList[i].r,fallList[i].deg,fallList[i].deg+Math.PI*1.3);
cxt.fill();
}
requestAnimationFrame(step);
}
requestAnimationFrame(step);
</script>
</body>
</html>

查看演示效果

更多特效,请关注我的微信公众号。

樱花的季节,教大家用canvas画出飞舞的樱花树的更多相关文章

  1. 撩妹技能 get,教你用 canvas 画一场流星雨

    开始 妹子都喜欢流星,如果她说不喜欢,那她一定是一个假妹子. 现在就一起来做一场流星雨,用程序员的野路子浪漫一下. 要画一场流星雨,首先,自然我们要会画一颗流星. 玩过 canvas 的同学,你画圆画 ...

  2. 情人节,教大家使用css画出一朵玫瑰花。

    情人节到了,给大家来一朵高端的玫瑰花. 在网上看到的一个canvas实现的玫瑰花,效果很好,但是代码被压缩过,也没有注释,看的云里雾里的. 今天我教大脚用CSS来实现一朵玫瑰花. 先看效果 首先我们画 ...

  3. 教你用SVG画出一条龙

    先看demo,九十七度 其实使用svg画出这条龙很简单,关键不在于怎么使用svg,而在于你的美术功底,哈哈. 好吧,当然基础是不能忽略的,先看下这条龙的代码: <svg id="lon ...

  4. 手对手的教你用canvas画一个简单的海报

    啦啦啦,首先说下需求,产品想让用户在我们app内,分享一张图片到微信.qq等平台.图片中包含用户的姓名.头像.和带着自己信息的二维码.然后,如何生成这张海报呢~~~首先我们老大告诉我有一个插件叫htm ...

  5. 公告栏添加时钟——利用canvas画出一个时钟

    前言 最近在学习HTML5标签,学到Canvas,觉得很有趣.便在慕课网找了个demo练手.就是Canvas时钟. 对于canvas,w3shcool上是这么描述的: HTML5 <canvas ...

  6. 4种方法生成二维码 (js 控制canvas 画出 二维码)

    随着网络的迅速发展 发展 发展,二维码的应用将会越来越多.同时很多只是很平凡的二维码,请拿起你的手 把这个二维码 设计起来吧.下面分享了几个非常好的二维码设计.  二维码原理: 二维条码/二维码可以分 ...

  7. 用canvas 画出圆形图片

    /** * 把图片处理成圆形,如果不是正方形就按最小边一半为半径处理 * @param {object} imgObj 图片(img)对象 * @param {number} imgType 设置生成 ...

  8. WPF在圆上画出刻度线

    思路 我们可以使用Ellipse先画出一个圆当背景,然后用Canvas再叠加画上刻度线,就能得到如下的效果 我们先用Ellipse画一个橙色的圆,然后将Canvas的宽度和高度绑定到Ellipse的宽 ...

  9. [示例] Firemonkey 画出 1 点像素的线

    说明:在 Firemonkey 在移动平台 Android & iOS 要直接在 Canvas 画出 1 点像素的线,似乎有点困难,不过利用一点小技巧,还是能达到这个要求的,首先要建立一个 B ...

随机推荐

  1. css浮动(float,clear)

    1. 以div元素布局为例,div是块级元素,在页面中独占一行,自上而下排列,也就是传说中的流,是指标准流中的div. 无论多么复杂的布局,其基本出发点均是:“如何在一行显示多个div元素”,显然标准 ...

  2. 获取app崩溃信息的途径 iOS

    获取崩溃日志的几种方法: 1.当用户抱怨闪退时,你可以要求他让设备与iTunes同步,设备与电脑上的iTunes Store同步后,会将崩溃日志保存在电脑上(路径:Mac OS X:~/Library ...

  3. matlab中hold指令、figure指令及subplot指令的使用

    一.hold指令使用 正常情况下,plot指令显示figure时,以前的数据丢失了.使用hold on指令后,此后添加的一系列plot曲线将叠加在前一个图上当使用hold off后,恢复为默认状况,p ...

  4. PHP中的 !== 与 !=

    '==' 比较两边的值是否相等,会自动转换类型: '===' 则会严格比较类型是否相同,如果类型不相同,直接返回false. 例如:'123' === 123 // => false '!=' ...

  5. git用法-打补丁

    1. git cherry-pick 作用:从一个branch上选择一个commit,添加该commit到另一个branch上. 1. 切换到你想添加commit的分支上. git checkout ...

  6. &与&& C语言

    &是一个位运算符,就是将两个二进制的数逐位相与,就是都是1才是1,只要有一个为0则为0,结果是相与之后的结果.&&是一个逻辑运算符,就是判断两个表达式的真假性,只有两个表达式同 ...

  7. 单线程JavaScript

    最近在阅读<你不知道的JavaScript中卷>,当我看到第二部分介绍异步和回调函数的一些知识时,由于该书在第二部分1.2章对线程.事件循环的概念介绍的并非详细,因此引发了我的一系列思考. ...

  8. 使用curl上传报错问题排查

    1. THE STOR COMMAND 说明存储出了问题,处理方案: 方案1: 请检查ftp服务器存储是否已满,若已满则清理一下空间即可. 方案2: 若ftp服务器存储未满,请检查是否有上传了的文件, ...

  9. Matlab将三维变量分割为多个二维变量的方法

    最近在处理 Matlab 中的三维矩阵的时候,遇到了一个问题: 假如m 为 5*5*5的矩阵,如果以第三个维度为基础,分割为5个不同的矩阵 m1,m2,m3,m4,应该如何解决? 解决方法:eval函 ...

  10. 【转】CXF+Spring+Eclipse简明示例

    多系统(异构系统)进行交互时,一种良好的方式便是调用Web Service,本示例基于Apache组织的CXF,为了方便起见特将服务端和客户端写在同一个工程下,实际项目中是不可能的,但是客户端却依赖于 ...