ripple.js 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177
  1. /**
  2. * Water ripple effect.
  3. * Original code (Java) by Neil Wallis
  4. * Code snipplet adapted to Javascript by Sergey Chikuyonok
  5. * Code re-written as jQuery plugin by Andy V.
  6. */
  7. ;(function ( $, window, document, undefined ) {
  8. var pluginName = "waterripple",
  9. defaults = {
  10. delay : 30, //delay before re-drawing the next frame
  11. riprad : 3, //single ripple radius
  12. line_width : 20,
  13. arbitrary : 1000, //generate a new random ripple every n-mseconds, false - turns off random ripples
  14. onclick : false, //generate a new ripple on mouse click
  15. onmove : false, //generate a new ripple on mouse move
  16. };
  17. function Plugin( element, options ) {
  18. this.element = element;
  19. this.options = $.extend( {}, defaults, options );
  20. this._defaults = defaults;
  21. this._name = pluginName;
  22. if(element.tagName == "IMG") {
  23. var imgSrc = $(this.element).attr("src");
  24. }
  25. else {
  26. var backgroundImage = $(this.element).css('background-image');
  27. if(backgroundImage != "none"){
  28. var pattern = /url\(['"]?(.+)['"]?\)/;
  29. var imgSrc = pattern.exec(backgroundImage)[1];
  30. }
  31. }
  32. if((typeof imgSrc !== 'undefined')) {
  33. var that = this;
  34. this.image = $("<img/>") // Make in memory copy of image to avoid css issues
  35. .attr("crossOrigin", "anonymous")
  36. .attr("src", imgSrc)
  37. .load(function() {
  38. that.init();
  39. });
  40. }
  41. }
  42. Plugin.prototype = {
  43. init: function() {
  44. var scope = {};
  45. scope.canvas = document.createElement('canvas');
  46. $(this.element).after(scope.canvas);
  47. scope.ctx = scope.canvas.getContext('2d');
  48. scope.width = $(this.element).width();
  49. scope.height = $(this.element).height();
  50. scope.delay = this.options.delay;
  51. scope.riprad = this.options.riprad;
  52. scope.line_width = this.options.line_width;
  53. scope.half_width = scope.width >> 1;
  54. scope.half_height = scope.height >> 1;
  55. scope.size = scope.width * (scope.height + 2) * 2;
  56. scope.oldind = scope.width;
  57. scope.newind = scope.width * (scope.height + 3);
  58. scope.mapind;
  59. scope.ripplemap = [];
  60. scope.last_map = [];
  61. scope.step = scope.line_width * 2;
  62. scope.count = scope.height / scope.line_width;
  63. scope.canvas.width = scope.width;
  64. scope.canvas.height = scope.height;
  65. scope.ctx.drawImage(this.image[0], 0, 0);
  66. $(this.element).hide();
  67. scope.texture = scope.ctx.getImageData(0, 0, scope.width, scope.height);
  68. scope.ripple = scope.ctx.getImageData(0, 0, scope.width, scope.height);
  69. for (var i = 0; i < scope.size; i++) {
  70. scope.last_map[i] = scope.ripplemap[i] = 0;
  71. }
  72. //run main loop
  73. setInterval(function() { run.call(scope); }, scope.delay);
  74. // generate random ripples
  75. if(this.options.arbitrary > 0) {
  76. var rnd = Math.random;
  77. disturb.call(scope, rnd() * scope.width, rnd() * scope.height);
  78. setInterval(function() {
  79. disturb.call(scope, rnd() * scope.width, rnd() * scope.height);
  80. }, this.options.arbitrary);
  81. }
  82. if(this.options.onclick) {
  83. scope.canvas.onclick = function(evt) {
  84. disturb.call(scope, evt.offsetX || evt.layerX, evt.offsetY || evt.layerY);
  85. };
  86. }
  87. if(this.options.onmove) {
  88. scope.canvas.onmousemove = function(evt) {
  89. disturb.call(scope, evt.offsetX || evt.layerX, evt.offsetY || evt.layerY);
  90. };
  91. }
  92. },
  93. };
  94. $.fn[pluginName] = function ( options ) {
  95. return this.each(function () {
  96. if (!$.data(this, "plugin_" + pluginName)) {
  97. $.data(this, "plugin_" + pluginName, new Plugin( this, options ));
  98. }
  99. });
  100. };
  101. /**
  102. * Main loop
  103. */
  104. function run() {
  105. newframe(this);
  106. this.ctx.putImageData(this.ripple, 0, 0);
  107. }
  108. /**
  109. * Disturb water at specified point
  110. */
  111. function disturb(dx, dy) {
  112. dx <<= 0;
  113. dy <<= 0;
  114. for (var j = dy - this.riprad; j < dy + this.riprad; j++) {
  115. for (var k = dx - this.riprad; k < dx + this.riprad; k++) {
  116. this.ripplemap[this.oldind + (j * this.width) + k] += 512;
  117. }
  118. }
  119. }
  120. /**
  121. * Generates new ripples
  122. */
  123. function newframe(scope) {
  124. var i, a, b, data, cur_pixel, new_pixel, old_data;
  125. i = scope.oldind;
  126. scope.oldind = scope.newind;
  127. scope.newind = i;
  128. i = 0;
  129. scope.mapind = scope.oldind;
  130. // create local copies of variables to decrease
  131. // scope lookup time in Firefox
  132. var _width = scope.width,
  133. _height = scope.height,
  134. _ripplemap = scope.ripplemap,
  135. _mapind = scope.mapind,
  136. _newind = scope.newind,
  137. _last_map = scope.last_map,
  138. _rd = scope.ripple.data,
  139. _td = scope.texture.data,
  140. _half_width = scope.half_width,
  141. _half_height = scope.half_height;
  142. for (var y = 0; y < _height; y++) {
  143. for (var x = 0; x < _width; x++) {
  144. data = (
  145. _ripplemap[_mapind - _width] +
  146. _ripplemap[_mapind + _width] +
  147. _ripplemap[_mapind - 1] +
  148. _ripplemap[_mapind + 1]) >> 1;
  149. data -= _ripplemap[_newind + i];
  150. data -= data >> 5;
  151. _ripplemap[_newind + i] = data;
  152. //where data=0 then still, where data>0 then wave
  153. data = 1024 - data;
  154. old_data = _last_map[i];
  155. _last_map[i] = data;
  156. if (old_data != data) {
  157. //offsets
  158. a = (((x - _half_width) * data / 1024) << 0) + _half_width;
  159. b = (((y - _half_height) * data / 1024) << 0) + _half_height;
  160. //bounds check
  161. if (a >= _width) a = _width - 1;
  162. if (a < 0) a = 0;
  163. if (b >= _height) b = _height - 1;
  164. if (b < 0) b = 0;
  165. new_pixel = (a + (b * _width)) * 4;
  166. cur_pixel = i * 4;
  167. _rd[cur_pixel] = _td[new_pixel];
  168. _rd[cur_pixel + 1] = _td[new_pixel + 1];
  169. _rd[cur_pixel + 2] = _td[new_pixel + 2];
  170. }
  171. ++_mapind;
  172. ++i;
  173. }
  174. }
  175. scope.mapind = _mapind;
  176. }
  177. })( jQuery, window, document );