1/* 2 Ken Burns effect JQuery plugin 3 Copyright (C) 2011 Will McGugan http://www.willmcgugan.com 4 5 This program is free software: you can redistribute it and/or modify 6 it under the terms of the GNU Affero General Public License as 7 published by the Free Software Foundation, either version 3 of the 8 License, or (at your option) any later version. 9 10 This program is distributed in the hope that it will be useful, 11 but WITHOUT ANY WARRANTY; without even the implied warranty of 12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 GNU Affero General Public License for more details. 14 15 You should have received a copy of the GNU Affero General Public License 16 along with this program. If not, see <http://www.gnu.org/licenses/>. 17*/ 18 19(function($){ 20 21 $.fn.kenburns = function(options) { 22 23 var $canvas = $(this); 24 var ctx = this[0].getContext('2d'); 25 var start_time = null; 26 var width = $canvas.width(); 27 var height = $canvas.height(); 28 29 var image_paths = options.images; 30 var display_time = options.display_time || 7000; 31 var fade_time = Math.min(display_time / 2, options.fade_time || 1000); 32 var solid_time = display_time - (fade_time * 2); 33 var fade_ratio = fade_time - display_time 34 var frames_per_second = options.frames_per_second || 30; 35 var frame_time = (1 / frames_per_second) * 1000; 36 var zoom_level = 1 / (options.zoom || 2); 37 var clear_color = options.background_color || '#000000'; 38 39 var images = []; 40 $(image_paths).each(function(i, image_path){ 41 images.push({path:image_path, 42 initialized:false, 43 loaded:false}); 44 }); 45 function get_time() { 46 var d = new Date(); 47 return d.getTime() - start_time; 48 } 49 50 function interpolate_point(x1, y1, x2, y2, i) { 51 // Finds a point between two other points 52 return {x: x1 + (x2 - x1) * i, 53 y: y1 + (y2 - y1) * i} 54 } 55 56 function interpolate_rect(r1, r2, i) { 57 // Blend one rect in to another 58 var p1 = interpolate_point(r1[0], r1[1], r2[0], r2[1], i); 59 var p2 = interpolate_point(r1[2], r1[3], r2[2], r2[3], i); 60 return [p1.x, p1.y, p2.x, p2.y]; 61 } 62 63 function scale_rect(r, scale) { 64 // Scale a rect around its center 65 var w = r[2] - r[0]; 66 var h = r[3] - r[1]; 67 var cx = (r[2] + r[0]) / 2; 68 var cy = (r[3] + r[1]) / 2; 69 var scalew = w * scale; 70 var scaleh = h * scale; 71 return [cx - scalew/2, 72 cy - scaleh/2, 73 cx + scalew/2, 74 cy + scaleh/2]; 75 } 76 77 function fit(src_w, src_h, dst_w, dst_h) { 78 // Finds the best-fit rect so that the destination can be covered 79 var src_a = src_w / src_h; 80 var dst_a = dst_w / dst_h; 81 var w = src_h * dst_a; 82 var h = src_h; 83 if (w > src_w) 84 { 85 var w = src_w; 86 var h = src_w / dst_a; 87 } 88 var x = (src_w - w) / 2; 89 var y = (src_h - h) / 2; 90 return [x, y, x+w, y+h]; 91 } 92 93 function get_image_info(image_index, load_callback) { 94 // Gets information structure for a given index 95 // Also loads the image asynchronously, if required 96 var image_info = images[image_index]; 97 if (!image_info.initialized) { 98 var image = new Image(); 99 image_info.image = image; 100 image_info.loaded = false; 101 image.onload = function(){ 102 image_info.loaded = true; 103 var iw = image.width; 104 var ih = image.height; 105 106 var r1 = fit(iw, ih, width, height);; 107 var r2 = scale_rect(r1, zoom_level); 108 109 var align_x = Math.floor(Math.random() * 3) - 1; 110 var align_y = Math.floor(Math.random() * 3) - 1; 111 align_x /= 2; 112 align_y /= 2; 113 114 var x = r2[0]; 115 r2[0] += x * align_x; 116 r2[2] += x * align_x; 117 118 var y = r2[1]; 119 r2[1] += y * align_y; 120 r2[3] += y * align_y; 121 122 if (image_index % 2) { 123 image_info.r1 = r1; 124 image_info.r2 = r2; 125 } 126 else { 127 image_info.r1 = r2; 128 image_info.r2 = r1; 129 } 130 131 if(load_callback) { 132 load_callback(); 133 } 134 135 } 136 image_info.initialized = true; 137 image.src = image_info.path; 138 } 139 return image_info; 140 } 141 142 function render_image(image_index, anim, fade) { 143 // Renders a frame of the effect 144 if (anim > 1) { 145 return; 146 } 147 var image_info = get_image_info(image_index); 148 if (image_info.loaded) { 149 var r = interpolate_rect(image_info.r1, image_info.r2, anim); 150 var transparency = Math.min(1, fade); 151 152 if (transparency > 0) { 153 ctx.save(); 154 ctx.globalAlpha = Math.min(1, transparency); 155 ctx.drawImage(image_info.image, r[0], r[1], r[2] - r[0], r[3] - r[1], 0, 0, width, height);
156 ctx.restore(); 157 } 158 } 159 } 160 161 function clear() { 162 // Clear the canvas 163 ctx.save(); 164 ctx.globalAlpha = 1; 165 ctx.fillStyle = clear_color; 166 ctx.fillRect(0, 0, ctx.canvas.width, ctx.canvas.height); 167 ctx.restore(); 168 } 169 170 function update() { 171 // Render the next frame 172 var update_time = get_time(); 173 174 var top_frame = Math.floor(update_time / (display_time - fade_time)); 175 var frame_start_time = top_frame * (display_time - fade_time); 176 var time_passed = update_time - frame_start_time; 177 178 function wrap_index(i) { 179 return (i + images.length) % images.length; 180 } 181 182 if (time_passed < fade_time) 183 { 184 var bottom_frame = top_frame - 1; 185 var bottom_frame_start_time = frame_start_time - display_time + fade_time; 186 var bottom_time_passed = update_time - bottom_frame_start_time; 187 if (update_time < fade_time) { 188 clear(); 189 } else { 190 render_image(wrap_index(bottom_frame), bottom_time_passed / display_time, 1); 191 } 192 } 193 194 render_image(wrap_index(top_frame), time_passed / display_time, time_passed / fade_time); 195 196 if (options.post_render_callback) { 197 options.post_render_callback($canvas, ctx); 198 } 199 200 // Pre-load the next image in the sequence, so it has loaded 201 // by the time we get to it 202 var preload_image = wrap_index(top_frame + 1); 203 get_image_info(preload_image); 204 } 205 206 // Pre-load the first two images then start a timer 207 get_image_info(0, function(){ 208 get_image_info(1, function(){ 209 start_time = get_time(); 210 setInterval(update, frame_time); 211 }) 212 }); 213 214 }; 215 216})( jQuery ); 217
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.