waterTank.js 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424
  1. /*!
  2. * jQuery 3D Watertank Plugin
  3. * Original author: @ajeeshvijay
  4. */
  5. (function ( $ ) {
  6. $.fn.waterTank = function( options ) {
  7. var settings = $.extend({
  8. color: "#6ecff6",
  9. level: 33
  10. }, options );
  11. function _updateTank($that, value){
  12. $that.find('._tank').fadeIn(1);
  13. $that.find('._balance').stop().animate({
  14. height: $that.find('._tank').height() * ( 100 - value ) / 100 ,
  15. },{
  16. duration: speed,
  17. step: function() { $that.find('._balance').css("overflow","visible"); },
  18. complete: function() { $that.find('._balance').css("overflow","visible"); }
  19. });
  20. $that.find('._filled').stop().animate({
  21. height: $that.find('._tank').height() * value / 100 ,
  22. opacity: 1
  23. },{
  24. duration: speed,
  25. step: function() { $that.find('._filled').css("overflow","visible"); },
  26. complete: function() { $that.find('._filled').css("overflow","visible"); }
  27. });
  28. // $that.find('._percentageTag').text(value + '%');
  29. // $that.find('._reflect').stop().animate({
  30. // height: ($that.find('._tank').height() * value / 100) / 2 + 20 ,
  31. // bottom: -($that.find('._tank').height() * value / 100) / 2 - 20,
  32. // },
  33. // speed
  34. // );
  35. if (value == 100) {
  36. $that.find('._topCircle').hide(0);
  37. }else{
  38. $that.find('._topCircle').show(0);
  39. }
  40. // setTimeout(function(){
  41. // $balance.css({
  42. // opacity: 1
  43. // });
  44. // }, 0);
  45. }
  46. var tilt = {
  47. '-webkit-transform' : 'rotateX(65deg) translateZ(0px)',
  48. '-moz-transform' : 'rotateX(65deg) translateZ(0px)',
  49. '-o-transform' : 'rotateX(65deg) translateZ(0px)',
  50. transform : 'rotateX(65deg) translateZ(0px)',
  51. '-moz-transform-style': 'preserve-3d',
  52. '-webkit-transform-style': 'preserve-3d',
  53. 'transform-style': 'preserve-3d',
  54. }
  55. var speed = 600;
  56. // Update
  57. if (options % 1 === 0) {
  58. // console.log(options);
  59. _updateTank($(this), options);
  60. }else{
  61. if ($(this).is(':empty')){
  62. var $tank = $('<div/>').appendTo(this);
  63. $tank.css({
  64. width: settings.width,
  65. height: settings.height,
  66. position: 'relative',
  67. margin: '50px auto',
  68. transform: 'translate3d(0,0,0)'
  69. }).addClass('_tank');
  70. // Balance
  71. var $balance = $('<div/>').appendTo($tank);
  72. $balance
  73. .css({
  74. height: settings.height,
  75. background: '#f2f2f1',
  76. position: 'relative',
  77. transform: 'translateZ(0px)',
  78. // opacity: .2
  79. })
  80. .addClass('_balance');
  81. var $balanceTopCircle = $('<div/>').appendTo($balance);
  82. $balanceTopCircle.css(
  83. Object.assign(
  84. {
  85. height: settings.width,
  86. width: '100%',
  87. background: '#f2f2f1',
  88. borderRadius: '50%',
  89. top: 0,
  90. marginTop: -(settings.width/2),
  91. position: 'absolute'
  92. },
  93. tilt
  94. )
  95. );
  96. var $topCircle = $('<div/>').appendTo($tank);
  97. $topCircle.css(
  98. Object.assign(
  99. {
  100. height: settings.width,
  101. width: '100%',
  102. background: 'rgba(255, 255, 255, .2)',
  103. borderRadius: '50%',
  104. top: 0,
  105. marginTop: -(settings.width/2),
  106. position: 'absolute',
  107. zIndex: 500,
  108. // opacity: .2,
  109. pointerEvents: 'none'
  110. },
  111. tilt
  112. )
  113. )
  114. .addClass('_topCircle');
  115. // Waterlevel
  116. var $filled = $('<div/>').appendTo($tank);
  117. $filled.css({
  118. height: 0 ,
  119. position: 'relative',
  120. opacity: 0,
  121. transform: 'translate3d(0,0,0)'
  122. })
  123. .addClass('_filled');
  124. var $filledBg = $('<div/>').appendTo($filled);
  125. $filledBg.css(
  126. Object.assign(
  127. {
  128. height: '100%',
  129. width: '100%',
  130. background: settings.color,
  131. position: 'absolute',
  132. opacity: .8,
  133. zIndex: 10
  134. }
  135. )
  136. );
  137. var $percentageTag = $('<div><div/>').appendTo($filledBg);
  138. // $percentageTag.css(
  139. // Object.assign(
  140. // {
  141. // position: 'absolute',
  142. // right: -85,
  143. // width: 70,
  144. // fontSize: 17,
  145. // top: -10,
  146. // textAlign: 'left'
  147. // }
  148. // )
  149. // ).addClass('_percentageTag').text(settings.level + '%');
  150. var $filledTopCircle = $('<div/>').appendTo($filled);
  151. $filledTopCircle.css(
  152. Object.assign(
  153. {
  154. height: settings.width,
  155. width: '100%',
  156. background: settings.color,
  157. borderRadius: '50%',
  158. top: 0,
  159. marginTop: -(settings.width/2),
  160. position: 'absolute',
  161. overflow: 'hidden',
  162. zIndex: 10
  163. },
  164. tilt
  165. )
  166. );
  167. var $canvas = $('<canvas/>').appendTo($filledTopCircle);
  168. // var $canvas = 0;
  169. $canvas.css({
  170. opacity: .8,
  171. transform: 'rotate(80deg)'
  172. });
  173. if ($canvas) {
  174. var canvas = $canvas.get(0),
  175. /** @type {CanvasRenderingContext2D} */
  176. ctx = canvas.getContext('2d'),
  177. width = settings.width,
  178. height = settings.width,
  179. half_width = width >> 1,
  180. half_height = height >> 1,
  181. size = width * (height + 2) * 2,
  182. delay = 30,
  183. oldind = width,
  184. newind = width * (height + 3),
  185. riprad = 8,
  186. ripplemap = [],
  187. last_map = [],
  188. ripple,
  189. texture,
  190. line_width = 1,
  191. step = line_width * 18,
  192. count = height / line_width;
  193. canvas.width = width;
  194. canvas.height = height;
  195. with (ctx) {
  196. fillStyle = settings.color;
  197. // fillStyle = 'skyblue';
  198. fillRect(0, 0, width, height);
  199. fillStyle = '#000';
  200. save();
  201. rotate(-0.785);
  202. // rotate(2);
  203. for (var i = 0; i < count; i++) {
  204. fillRect(-width, i * step, width * 3, line_width);
  205. }
  206. restore();
  207. }
  208. texture = ctx.getImageData(0, 0, width, height);
  209. ripple = ctx.getImageData(0, 0, width, height);
  210. for (var i = 0; i < size; i++) {
  211. last_map[i] = ripplemap[i] = 0;
  212. }
  213. /**
  214. * Main loop
  215. */
  216. function run() {
  217. newframe();
  218. ctx.putImageData(ripple, 0, 0);
  219. }
  220. /**
  221. * Disturb water at specified point
  222. */
  223. function disturb(dx, dy) {
  224. dx <<= 0;
  225. dy <<= 0;
  226. for (var j = dy - riprad; j < dy + riprad; j++) {
  227. for (var k = dx - riprad; k < dx + riprad; k++) {
  228. ripplemap[oldind + (j * width) + k] += 128;
  229. }
  230. }
  231. }
  232. /**
  233. * Generates new ripples
  234. */
  235. function newframe() {
  236. var a, b, data, cur_pixel, new_pixel, old_data;
  237. var t = oldind; oldind = newind; newind = t;
  238. var i = 0;
  239. // create local copies of variables to decrease
  240. // scope lookup time in Firefox
  241. var _width = width,
  242. _height = height,
  243. _ripplemap = ripplemap,
  244. _last_map = last_map,
  245. _rd = ripple.data,
  246. _td = texture.data,
  247. _half_width = half_width,
  248. _half_height = half_height;
  249. for (var y = 0; y < _height; y++) {
  250. for (var x = 0; x < _width; x++) {
  251. var _newind = newind + i, _mapind = oldind + i;
  252. data = (
  253. _ripplemap[_mapind - _width] +
  254. _ripplemap[_mapind + _width] +
  255. _ripplemap[_mapind - 1] +
  256. _ripplemap[_mapind + 1]) >> 1;
  257. data -= _ripplemap[_newind];
  258. data -= data >> 5;
  259. _ripplemap[_newind] = data;
  260. //where data=0 then still, where data>0 then wave
  261. data = 1024 - data;
  262. old_data = _last_map[i];
  263. _last_map[i] = data;
  264. if (old_data != data) {
  265. //offsets
  266. a = (((x - _half_width) * data / 1024) << 0) + _half_width;
  267. b = (((y - _half_height) * data / 1024) << 0) + _half_height;
  268. //bounds check
  269. if (a >= _width) a = _width - 1;
  270. if (a < 0) a = 0;
  271. if (b >= _height) b = _height - 1;
  272. if (b < 0) b = 0;
  273. new_pixel = (a + (b * _width)) * 4;
  274. cur_pixel = i * 4;
  275. _rd[cur_pixel] = _td[new_pixel];
  276. _rd[cur_pixel + 1] = _td[new_pixel + 1];
  277. _rd[cur_pixel + 2] = _td[new_pixel + 2];
  278. }
  279. ++i;
  280. }
  281. }
  282. }
  283. canvas.onmousemove = function(/* Event */ evt) {
  284. disturb(evt.offsetX || evt.layerX, evt.offsetY || evt.layerY);
  285. };
  286. if (settings.level >= 0) {
  287. setInterval(run, delay);
  288. // generate random ripples
  289. var rnd = Math.random;
  290. setInterval(function() {
  291. disturb(rnd() * width, rnd() * height);
  292. }, 700);
  293. }
  294. }
  295. var $filledBottomCircle = $('<div/>').appendTo($filled);
  296. $filledBottomCircle.css(
  297. Object.assign(
  298. {
  299. height: settings.width,
  300. width: '100%',
  301. background: settings.color,
  302. borderRadius: '50%',
  303. bottom: 0,
  304. marginBottom: -(settings.width/2),
  305. position: 'absolute',
  306. // boxShadow: 'rgba(0, 0, 0, 0.3) 0px 15px 50px'
  307. },
  308. tilt
  309. )
  310. );
  311. var $reflect = $('<div/>').appendTo($filled);
  312. $reflect.addClass('_reflect');
  313. // console.log((settings.height * (100 - settings.level)));
  314. $reflect.css('background', '-moz-linear-gradient(top, '+settings.color+') 0%, rgba(255,255,255,0) 100%)');
  315. $reflect.css('background', '-webkit-linear-gradient(top, '+settings.color+' 0%,rgba(255,255,255,0) 100%)');
  316. $reflect.css('background', 'linear-gradient(to bottom, '+settings.color+' 0%,rgba(255,255,255,0) 100%)');
  317. $reflect.css({
  318. position: 'absolute',
  319. width: '100%',
  320. // height: settings.width/2,
  321. // bottom: -(settings.width/2),
  322. height: ((settings.height * (100-settings.level) / 100)),
  323. // bottom: -((settings.height * (100-settings.level) / 100)/2),
  324. opacity: .4
  325. });
  326. }else{
  327. var $tank = $(this).find('_tank');
  328. var $balance = $(this).find('_balance');
  329. var $filled = $(this).find('_filled');
  330. }
  331. $tank.fadeOut(0);
  332. var _this = $(this)
  333. setTimeout(function(){
  334. _updateTank(_this, settings.level);
  335. }, 300);
  336. }
  337. return this;
  338. };
  339. }( jQuery ));