今天,我们继续分享 JavaScript 实现的效果例子,这篇文章会介绍使用 JavaScript 实现水波纹效果。水波效果以图片为背景,点击图片任意位置都会触发。有时候,我们使用普通的 Javascript 就可以创建一个很有趣的解决功能。
Step 1. HTML
和以前一样,首先是 HTML 代码:
- <!DOCTYPE html>
-
- <html>
-
- <head>
-
- <meta charset=utf-8 />
-
- <title>Water drops effect</title>
-
- <link rel="stylesheet" href="css/main.css" type="text/css" />
-
- <script src="js/vector2d.js" type="text/javascript" charset="utf-8"></script>
-
- <script src="js/waterfall.js" type="text/javascript" charset="utf-8"></script>
-
- </head>
-
- <body>
-
- <div class="example">
-
- <h3><a href="#">Water drops effect</a></h3>
-
-
-
- <canvas id="water">HTML5 compliant browser required</canvas>
-
- <div id="switcher">
-
- <img οnclick='watereff.changePicture(this.src);' src="data_images/underwater1.jpg" />
-
- <img οnclick='watereff.changePicture(this.src);' src="data_images/underwater2.jpg" />
-
- </div>
-
- <div id="fps"></div>
-
- </div>
-
- </body>
-
- </html>
Step 2. CSS
这是用到的 CSS 代码:
- body{background:#eee;margin:0;padding:0}
-
- .example{background:#FFF;width:600px;border:1px #000 solid;margin:20px auto;padding:15px;-moz-border-radius: 3px;-webkit-border-radius: 3px}
-
-
-
- #water {
-
- width:500px;
-
- height:400px;
-
- display: block;
-
- margin:0px auto;
-
- cursor:pointer;
-
- }
-
- #switcher {
-
- text-align:center;
-
- overflow:hidden;
-
- margin:15px;
-
- }
-
- #switcher img {
-
- width:160px;
-
- height:120px;
-
- }
Step 3. JS
下面是主要的 JavaScript 代码:
- function drop(x, y, damping, shading, refraction, ctx, screenWidth, screenHeight){
-
- this.x = x;
-
- this.y = y;
-
- this.shading = shading;
-
- this.refraction = refraction;
-
- this.bufferSize = this.x * this.y;
-
- this.damping = damping;
-
- this.background = ctx.getImageData(0, 0, screenWidth, screenHeight).data;
-
- this.imageData = ctx.getImageData(0, 0, screenWidth, screenHeight);
-
-
-
- this.buffer1 = [];
-
- this.buffer2 = [];
-
- for (var i = 0; i < this.bufferSize; i++){
-
- this.buffer1.push(0);
-
- this.buffer2.push(0);
-
- }
-
-
-
- this.update = function(){
-
- for (var i = this.x + 1, x = 1; i < this.bufferSize - this.x; i++, x++){
-
- if ((x < this.x)){
-
- this.buffer2[i] = ((this.buffer1[i - 1] + this.buffer1[i + 1] + this.buffer1[i - this.x] + this.buffer1[i + this.x]) / 2) - this.buffer2[i];
-
- this.buffer2[i] *= this.damping;
-
- } else x = 0;
-
- }
-
-
-
- var temp = this.buffer1;
-
- this.buffer1 = this.buffer2;
-
- this.buffer2 = temp;
-
- }
-
-
-
- this.draw = function(ctx){
-
- var imageDataArray = this.imageData.data;
-
- for (var i = this.x + 1, index = (this.x + 1) * 4; i < this.bufferSize - (1 + this.x); i++, index += 4){
-
- var xOffset = ~~(this.buffer1[i - 1] - this.buffer1[i + 1]);
-
- var yOffset = ~~(this.buffer1[i - this.x] - this.buffer1[i + this.x]);
-
- var shade = xOffset * this.shading;
-
- var texture = index + (xOffset * this.refraction + yOffset * this.refraction * this.x) * 4;
-
- imageDataArray[index] = this.background[texture] + shade;
-
- imageDataArray[index + 1] = this.background[texture + 1] + shade;
-
- imageDataArray[index + 2] = 50 + this.background[texture + 2] + shade;
-
- }
-
- ctx.putImageData(this.imageData, 0, 0);
-
- }
-
- }
-
-
-
- var fps = 0;
-
-
-
- var watereff = {
-
- // variables
-
- timeStep : 20,
-
- refractions : 2,
-
- shading : 3,
-
- damping : 0.99,
-
- screenWidth : 500,
-
- screenHeight : 400,
-
- pond : null,
-
- textureImg : null,
-
- interval : null,
-
- backgroundURL : 'data_images/underwater1.jpg',
-
-
-
- // initialization
-
- init : function() {
-
- var canvas = document.getElementById('water');
-
- if (canvas.getContext){
-
-
-
- // fps countrt
-
- fps = 0;
-
- setInterval(function() {
-
- document.getElementById('fps').innerHTML = fps / 2 + ' FPS';
-
- fps = 0;
-
- }, 2000);
-
-
-
- canvas.onmousedown = function(e) {
-
- var mouse = watereff.getMousePosition(e).sub(new vector2d(canvas.offsetLeft, canvas.offsetTop));
-
- watereff.pond.buffer1[mouse.y * watereff.pond.x + mouse.x ] += 200;
-
- }
-
- canvas.onmouseup = function(e) {
-
- canvas.onmousemove = null;
-
- }
-
-
-
- canvas.width = this.screenWidth;
-
- canvas.height = this.screenHeight;
-
- this.textureImg = new Image(256, 256);
-
- this.textureImg.src = this.backgroundURL;
-
- canvas.getContext('2d').drawImage(this.textureImg, 0, 0);
-
- this.pond = new drop(
-
- this.screenWidth,
-
- this.screenHeight,
-
- this.damping,
-
- this.shading,
-
- this.refractions,
-
- canvas.getContext('2d'),
-
- this.screenWidth, this.screenHeight
-
- );
-
- if (this.interval != null){
-
- clearInterval(this.interval);
-
- }
-
- this.interval = setInterval(watereff.run, this.timeStep);
-
- }
-
- },
-
-
-
- // change image func
-
- changePicture : function(url){
-
- this.backgroundURL = url;
-
- this.init();
-
- },
-
-
-
- // get mouse position func
-
- getMousePosition : function(e){
-
- if (!e){
-
- var e = window.event;
-
- }
-
- if (e.pageX || e.pageY){
-
- return new vector2d(e.pageX, e.pageY);
-
- } else if (e.clientX || e.clientY){
-
- return new vector2d(e.clientX, e.clientY);
-
- }
-
- },
-
-
-
- // loop drawing
-
- run : function(){
-
- var ctx = document.getElementById('water').getContext('2d');
-
- watereff.pond.update();
-
- watereff.pond.draw(ctx);
-
- fps++;
-
- }
-
- }
-
-
-
- window.onload = function(){
-
- watereff.init();
-
- }
正如你所看到的,这里使用 Vector2D 函数,这个函数在 vector2d.js 里提供了。另一个很难的方法是使用纯数学实现,感兴趣的可以自己实验一下。