PageSourceSearch

https://yappo.github.io/talks/20140903-groonga-conoha/js/impress.js

js yappo.github.io collected 2026-10-03 10:12:33 UTC 10,071 bytes, 340 lines download raw bytes

1/**
2 * impress.js
3 *
4 * impress.js is a presentation tool based on the power of CSS3 transforms and transitions
5 * in modern browsers and inspired by the idea behind prezi.com.
6 *
7 * MIT Licensed.
8 *
9 * Copyright 2011 Bartek Szopka (@bartaz)
10 */
11
12(function ( document, window ) {
13    'use strict';
14
15    // HELPER FUNCTIONS
16    
17    var pfx = (function () {
18
19        var style = document.createElement('dummy').style,
20            prefixes = 'Webkit Moz O ms Khtml'.split(' '),
21            memory = {};
22            
23        return function ( prop ) {
24            if ( typeof memory[ prop ] === "undefined" ) {
25
26                var ucProp  = prop.charAt(0).toUpperCase() + prop.substr(1),
27                    props   = (prop + ' ' + prefixes.join(ucProp + ' ') + ucProp).split(' ');
28
29                memory[ prop ] = null;
30                for ( var i in props ) {
31                    if ( style[ props[i] ] !== undefined ) {
32                        memory[ prop ] = props[i];
33                        break;
34                    }
35                }
36
37            }
38
39            return memory[ prop ];
40        }
41
42    })();
43
44    var arrayify = function ( a ) {
45        return [].slice.call( a );
46    };
47    
48    var css = function ( el, props ) {
49        var key, pkey;
50        for ( key in props ) {
51            if ( props.hasOwnProperty(key) ) {
52                pkey = pfx(key);
53                if ( pkey != null ) {
54                    el.style[pkey] = props[key];
55                }
56            }
57        }
58        return el;
59    }
60    
61    var byId = function ( id ) {
62        return document.getElementById(id);
63    }
64    
65    var $ = function ( selector, context ) {
66        context = context || document;
67        return context.querySelector(selector);
68    };
69    
70    var $$ = function ( selector, context ) {
71        context = context || document;
72        return arrayify( context.querySelectorAll(selector) );
73    };
74    
75    var translate = function ( t ) {
76        return " translate3d(" + t.x + "px," + t.y + "px," + t.z + "px) ";
77    };
78    
79    var rotate = function ( r, revert ) {
80        var rX = " rotateX(" + r.x + "deg) ",
81            rY = " rotateY(" + r.y + "deg) ",
82            rZ = " rotateZ(" + r.z + "deg) ";
83        
84        return revert ? rZ+rY+rX : rX+rY+rZ;
85    };
86    
87    var scale = function ( s ) {
88        return " scale(" + s + ") ";
89    }
90    
91    // CHECK SUPPORT
92    
93    var ua = navigator.userAgent.toLowerCase();
94    var impressSupported = ( pfx("perspective") != null ) &&
95                           ( ua.search(/(iphone)|(ipod)|(ipad)|(android)/) == -1 );
96    
97    // DOM ELEMENTS
98    
99    var impress = byId("impress");
100    
101    if (!impressSupported) {
102        impress.className = "impress-not-supported";
103        return;
104    } else {
105        impress.className = "";
106    }
107    
108    var canvas = document.createElement("div");
109    canvas.className = "canvas";
110    
111    arrayify( impress.childNodes ).forEach(function ( el ) {
112        canvas.appendChild( el );
113    });
114    impress.appendChild(canvas);
115    
116    var steps = $$(".step", impress);
117    
118    // SETUP
119    // set initial values and defaults
120    
121    document.documentElement.style.height = "100%";
122    
123    css(document.body, {
124        height: "100%",
125        overflow: "hidden"
126    });
127
128    var props = {
129        position: "absolute",
130        transformOrigin: "top left",
131        transition: "all 0s ease-in-out",
132        transformStyle: "preserve-3d"
133    }
134    
135    css(impress, props);
136    css(impress, {
137        top: "50%",
138        left: "50%",
139        perspective: "1000px"
140    });
141    css(canvas, props);
142    
143    var current = {
144        translate: { x: 0, y: 0, z: 0 },
145        rotate:    { x: 0, y: 0, z: 0 },
146        scale:     1
147    };
148
149    steps.forEach(function ( el, idx ) {
150        var data = el.dataset,
151            step = {
152                translate: {
153                    x: data.x || 0,
154                    y: data.y || 0,
155                    z: data.z || 0
156                },
157                rotate: {
158                    x: data.rotateX || 0,
159                    y: data.rotateY || 0,
160                    z: data.rotateZ || data.rotate || 0
161                },
162                scale: data.scale || 1
163            };
164        
165        el.stepData = step;
166        
167        if ( !el.id ) {
168            el.id = "step-" + (idx + 1);
169        }
170        
171        css(el, {
172            position: "absolute",
173            transform: "translate(-50%,-50%)" +
174                       translate(step.translate) +
175                       rotate(step.rotate) +
176                       scale(step.scale),
177            transformStyle: "preserve-3d"
178        });
179        
180    });
181
182    // making given step active
183
184    var active = null;
185    var hashTimeout = null;
186    
187    var select = function ( el ) {
188        if ( !el || !el.stepData || el == active) {
189            // selected element is not defined as step or is already active
190            return false;
191        }
192        
193        // Sometimes it's possible to trigger focus on first link with some keyboard action.
194        // Browser in such a case tries to scroll the page to make this element visible
195        // (even that body overflow is set to hidden) and it breaks our careful positioning.
196        //
197        // So, as a lousy (and lazy) workaround we will make the page scroll back to the top
198        // whenever slide is selected
199        //
200        // If you are reading this and know any better way to handle it, I'll be glad to hear about it!
201        window.scrollTo(0, 0);
202        
203        var step = el.stepData;
204        
205        if ( active ) {
206            active.classList.remove("active");
207        }
208        el.classList.add("active");
209        
210        impress.className = "step-" + el.id;
211        
212        // `#/step-id` is used instead of `#step-id` to prevent default browser
213        // scrolling to element in hash
214        //
215        // and it has to be set after animation finishes, because in chrome it
216        // causes transtion being laggy
217        window.clearTimeout( hashTimeout );
218        hashTimeout = window.setTimeout(function () {
219            window.location.hash = "#/" + el.id;
220        }, 1000);
221        
222        var target = {
223            rotate: {
224                x: -parseInt(step.rotate.x, 10),
225                y: -parseInt(step.rotate.y, 10),
226                z: -parseInt(step.rotate.z, 10)
227            },
228            translate: {
229                x: -step.translate.x,
230                y: -step.translate.y,
231                z: -step.translate.z
232            },
233            scale: 1 / parseFloat(step.scale)
234        };
235        
236        // check if the transition is zooming in or not
237        var zoomin = target.scale >= current.scale;
238        
239        // if presentation starts (nothing is active yet)
240        // don't animate (set duration to 0)
241        var duration = (active) ? "600ms" : "0";
242        
243        css(impress, {
244            // to keep the perspective look similar for different scales
245            // we need to 'scale' the perspective, too
246            perspective: step.scale * 1000 + "px",
247            transform: scale(target.scale),
248            transitionDuration: duration,
249            transitionDelay: (zoomin ? "500ms" : "0ms")
250        });
251        
252        css(canvas, {
253            transform: rotate(target.rotate, true) + translate(target.translate),
254            transitionDuration: duration,
255            transitionDelay: (zoomin ? "0ms" : "500ms")
256        });
257        
258        current = target;
259        active = el;
260        
261        return el;
262    };
263    
264    var selectPrev = function () {
265        var prev = steps.indexOf( active ) - 1;
266        prev = prev >= 0 ? steps[ prev ] : steps[ steps.length-1 ];
267        
268        return select(prev);
269    };
270    
271    var selectNext = function () {
272        var next = steps.indexOf( active ) + 1;
273        next = next < steps.length ? steps[ next ] : steps[ 0 ];
274        
275        return select(next);
276    };
277    
278    // EVENTS
279    
280    document.addEventListener("keydown", function ( event ) {
281        if ( event.keyCode == 9 || ( event.keyCode >= 32 && event.keyCode <= 34 ) || (event.keyCode >= 37 && event.keyCode <= 40) ) {
282            switch( event.keyCode ) {
283                case 33: ; // pg up
284                case 37: ; // left
285                case 38:   // up
286                         selectPrev();
287                         break;
288                case 9:  ; // tab
289                case 32: ; // space
290                case 34: ; // pg down
291                case 39: ; // right
292                case 40:   // down
293                         selectNext();
294                         break;
295            }
296            
297            event.preventDefault();
298        }
299    }, false);
300
301    document.addEventListener("click", function ( event ) {
302        // event delegation with "bubbling"
303        // check if event target (or any of its parents is a link or a step)
304        var target = event.target;
305        while ( (target.tagName != "A") &&
306                (!target.stepData) &&
307                (target != document.body) ) {
308            target = target.parentNode;
309        }
310        
311        if ( target.tagName == "A" ) {
312            var href = target.getAttribute("href");
313            
314            // if it's a link to presentation step, target this step
315            if ( href && href[0] == '#' ) {
316                target = byId( href.slice(1) );
317            }
318        }
319        
320        if ( select(target) ) {
321            event.preventDefault();
322        }
323    }, false);
324    
325    var getElementFromUrl = function () {
326        // get id from url # by removing `#` or `#/` from the beginning,
327        // so both "fallback" `#slide-id` and "enhanced" `#/slide-id` will work
328        return byId( window.location.hash.replace(/^#\/?/,"") );
329    }
330    
331    window.addEventListener("hashchange", function () {
332        select( getElementFromUrl() );
333    }, false);
334    
335    // START 
336    // by selecting step defined in url or first step of the presentation
337    select(getElementFromUrl() || steps[0]);
338
339})(document, window);
340

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.