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