又到了樱花的季节,教大家使用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. CSS3 3D变形效果

    CSS3 3D变形效果 CSS3 transform3D变形 transform的含义是:改变,使-变形:转换 三维变换使用基于二维变换的相同属性,如果您熟悉二维变换,你们发现3D变形的功能和2D变换 ...

  2. iOS获取本地时间

    NSDate *currentDate = [NSDate date];//获取当前时间,日期 NSDateFormatter *dateFormatter = [[NSDateFormatter a ...

  3. swift注意

    赋值的时候要想为空 可以用   ? 例如 var age1:Int? // ?表示age1的类型为可选类型,其值可以为空print(age1) 判断一个字符串为空字符串if str_empty.isE ...

  4. 你需要了解的 Core Spotlight

    你需要了解的 Core Spotlight -- 了解Spotlight Core Spotlight是iOS 9中苹果推出了新的Search API,可以直接搜App内的内容(in-App Sear ...

  5. 偶遇event.target

    今天在学习其他人代码的时候见到了event.target.nodeName,event.target.dataset.刚开始是一头雾水,便google一下.发现大多数给出的词条都是有关jQuery事件 ...

  6. mysql常用语法

    创建表 create table <表名>( <字段名>  类型(长度) not null primary key auto_increment, **主键 name char ...

  7. vue路由组件群

    import Vue from 'vue'import VueRouter from 'vue-router'Vue.use(VueRouter) const first = { template: ...

  8. lambda表达式查询经验:IN 和groupby的使用

    lambda In的用法: lambda表达式查询没有IN这个方法,可以变通一下,in查询的数组是否包含在映射对象里面的集合里: 如下代码: var departmentIDs = input.Dep ...

  9. esri-leaflet入门教程(5)- 动态要素加载

    esri-leaflet入门教程(5)- 动态要素加载 by 李远祥 在上一章节中已经说明了esr-leaflet是如何加载ArcGIS Server提供的各种服务,这些都是服务本身来决定的,API脚 ...

  10. AlloyTouch之select选择插件

    原文地址:https://github.com/AlloyTeam/AlloyTouch/wiki/Simple-Select 写在前面 很多情况下,产品希望统一安卓和IOS select交互和样式. ...