预览地址:http://bl.ocks.org/chengquan223/raw/505d935f54bf0fe86195642464e77ce7/
<style type="text/css"> canvas { margin: 20px 0; } </style> <h1>小蝌蚪模拟风场</h1> <canvas id="canvas" width=700 height=500 style="border: 1px solid #ccc;"></canvas>
javascript
<script> $(function () { var Arrow = function (x, y, angle, speed, alive) { this.x = x; this.y = y; this.angle = angle; //游走方向 this.swingAngle = 6; //尾巴摆动角度 this.speed = speed || 8; //小蝌蚪长度来代表速度 this.alive = alive || true; //是否活着 this.liveLength = Math.random() * 10 + 20; //生命长度 }; self.init = function () { this.canvas = document.getElementById('canvas'); this.ctx = canvas.getContext('2d'); this.cw = this.canvas.width; this.ch = this.canvas.height; this.arrows = this.initArrows(); }; self.initArrows = function () { var count = 200, arrowArray = [], arrow = {}; while (count--) { arrow = new Arrow(Math.random() * this.cw, Math.random() * this.ch, Math.random() * 360, 8, true); arrowArray.push(arrow); } return arrowArray; }; self.createArrows = function () { this.ctx.clearRect(0, 0, this.cw, this.ch); var i = this.arrows.length; while (i--) { var arrow = this.arrows[i]; arrow.reset(); arrow.alive ? arrow.draw() : arrow.relive(); } }; Arrow.prototype.reset = function () { this.liveLength--; if (this.liveLength <= 0) { this.alive = false; } if (this.x < 0 || this.y < 0 || this.x > self.cw || this.y > self.ch) { this.alive = false; } }; Arrow.prototype.draw = function () { var ex = ey = 0; ex = this.x - this.speed * Math.sin((180 - this.angle + this.swingAngle) * (Math.PI / 180)); //↓0°←90° ey = this.y - this.speed * Math.cos((180 - this.angle + this.swingAngle) * (Math.PI / 180)); ctx.beginPath(); ctx.translate(0, 0, 0); //坐标源点 ctx.moveTo(this.x, this.y); ctx.lineTo(ex, ey); ctx.fill(); ctx.stroke(); ctx.save(); ctx.translate(ex, ey); //我的箭头本垂直向下,算出直线偏离Y的角,然后旋转 ,rotate是顺时针旋转的,所以加个负号 var ang = (ex - this.x) / (ey - this.y); ang = Math.atan(ang); ey - this.y >= 0 ? ctx.rotate(-ang) : ctx.rotate(Math.PI - ang);//加个180度,反过来 ctx.lineTo(-2, -2); ctx.lineTo(0, -3); ctx.lineTo(2, -2); ctx.lineTo(0, 0); ctx.fill(); //箭头是个封闭图形 ctx.restore(); //用来恢复Canvas之前保存的状态,否则会影响后续绘制 ctx.closePath(); this.x = ex; //终点当起点 this.y = ey; this.swingAngle *= -1; //摆动角度正反互换 }; Arrow.prototype.relive = function () { this.alive = true; this.x = Math.random() * self.cw; this.y = Math.random() * self.ch; this.liveLength = Math.random() * 20; }; var animateArrow = function () { self.createArrows(); }; self.init(); animateArrow(); var timer = setInterval(animateArrow, 170); }); </script>