Created
August 20, 2010 11:02
-
-
Save timyates/540074 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
(function( $ ) { | |
var defaults = { | |
image : 'water.png', | |
damping : 4, | |
dripSize : 9, | |
dripDepth : 250 | |
}; | |
var options ; | |
var canvas ; | |
var top = 0 ; | |
var left = 0 ; | |
var ctx ; | |
var img ; | |
var width ; | |
var height ; | |
var halfWidth ; | |
var halfHeight ; | |
var offsets = [] ; | |
var buffer = [] ; | |
var start ; | |
var end ; | |
var imageData ; | |
var surface ; | |
var surfaceData ; | |
$.fn.liquify = function( opts ) { | |
canvas = $(this) ; | |
options = $.extend( defaults, opts ) ; | |
top = canvas.offset().top ; | |
left = canvas.offset().left ; | |
ctx = canvas.get(0).getContext("2d"); | |
img = new Image(); | |
img.onload = init ; | |
img.src = options.image ; | |
} | |
var init = function() { | |
width = canvas.get( 0 ).width = img.width ; | |
height = canvas.get( 0 ).height = img.height ; | |
halfWidth = width >> 1 ; | |
halfHeight = height >> 1 ; | |
offsets = [] | |
for( i = 0 ; i < height ; i++ ) { | |
offsets.push( i * width * 4 ) ; | |
} | |
buffer = [] | |
for( i = 0 ; i < width * ( height + 2 ) * 2 ; i++ ) { | |
buffer.push( 0 ) ; | |
} | |
start = width ; | |
end = width * ( height + 3 ) ; | |
canvas.mousemove( mouseMove ) | |
ctx.clearRect( 0, 0, width, height ) ; | |
ctx.drawImage( img, 0, 0, width, height ) ; | |
imageData = ctx.getImageData( 0, 0, width, height ).data ; | |
surface = ctx.createImageData( width, height ) ; | |
surfaceData = surface.data ; | |
ctx.putImageData( surface, 0, 0 ) ; | |
setTimeout( function() { loop() }, 1 ) ; | |
} | |
var mouseMove = function( e ) { | |
var x = e.clientX - left ; | |
var y = e.clientY - top ; | |
x -= options.dripSize >> 1 ; | |
y -= options.dripSize >> 1 ; | |
if( x > width - options.dripSize ) x = width - options.dripSize ; | |
if( x < 0 ) x = 0 ; | |
if( y > height - options.dripSize ) y = height - options.dripSize ; | |
if( y < 0 ) y = 0 ; | |
addRipple( x, y ) | |
} | |
var addRipple = function( x, y ) { | |
var size = options.dripSize ; | |
var depth = options.dripDepth ; | |
for( xx = 0 ; xx < size ; xx++ ) { | |
for( yy = 0 ; yy <= size ; yy++ ) { | |
if( y + xx + 1 > 0 && y + xx + 1 < height - size ) { | |
buffer[ end + ( offsets[ y + xx ] >> 2 ) + x + yy ] += depth ; | |
} | |
} | |
} | |
} | |
var loop = function() { | |
process() ; | |
swap() ; | |
setTimeout( function() { loop() }, 20 ) ; | |
} | |
var swap = function() { | |
var tmp = start ; | |
start = end ; | |
end = tmp ; | |
} | |
var process = function() { | |
var st = start ; | |
var pos = 0 ; | |
var en = end ; | |
var damp = options.damping ; | |
var rnd = Math.floor( Math.random() * 255 ) ; | |
for( y = 0 ; y < height ; y++ ) { | |
for( x = 0 ; x < width ; x++ ) { | |
var val = ( buffer[ st - width ] + | |
buffer[ st + width ] + | |
buffer[ st - 1 ] + | |
buffer[ st + 1 ] ) ; | |
val = val >> 1 ; | |
val -= buffer[ en ] ; | |
val -= val >> damp ; | |
buffer[ en++ ] = val ; | |
val = 1024 - val ; | |
var dx = ( ( x - halfWidth ) * val >> 10 ) + halfWidth ; | |
dx = dx < width ? dx >= 0 ? dx : 0 : width - 1 ; | |
var dy = ( ( y - halfHeight ) * val >> 10 ) + halfHeight ; | |
dy = dy < height ? dy >= 0 ? dy : 0 : height - 1 ; | |
var ps = ( ( dx * 4 ) + offsets[ dy ] ) ; | |
ps = ps < 0 ? 0 : ps >= imageData.length - 4 ? imageData.length - 5 : ps ; | |
for( i = 0 ; i < 4 ; i++ ) { | |
surfaceData[ pos + i ] = imageData[ ps + i ] ; | |
} | |
pos += 4 ; | |
st++ ; | |
} | |
} | |
ctx.putImageData( surface, 0, 0 ) ; | |
} | |
})( jQuery ) ; | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<html> | |
<head> | |
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js" type="text/javascript"></script> | |
<script src="jquery-durius-water.js" type="text/javascript"></script> | |
<title>Water</title> | |
</head> | |
<body> | |
<canvas id='water'></canvas> | |
</body> | |
<script type="text/javascript"> | |
$(document).ready( function() { | |
$('#water').liquify( { | |
image: 'logo.jpg' | |
} ) ; | |
} ) ; | |
</script> | |
</html> |
Please note as well, that this code is slow.
This could be due to:
- shoddy programming by me
- the amount of processing it has to do
or the speed of the putImageData call
I haven't done any profiling to find out which one it is (though I suspect a bit of each)
Improved the speed by getting rid of all the options.XXX calls, and just having internal vars for each property
Also, changed surface.data[] to surfaceData inside the main processing loop
This actually runs quite fast on Chrome now, sluggishly on Safari, and like a sock cutting through treacle on Firefox
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Actually, the image property has to be a local image url to avoid a security exception