impressive api merged
This commit is contained in:
@@ -24,7 +24,12 @@ VERSION HISTORY
|
||||
|
||||
**CONTAINS UNRELEASED CHANGES, MAY BE UNSTABLE**
|
||||
|
||||
<<<<<<< HEAD
|
||||
* minor CSS 3D fixes
|
||||
=======
|
||||
* basic API to control the presentation flow from JavaScript
|
||||
* touch event support
|
||||
>>>>>>> api
|
||||
|
||||
### 0.2 ([browse](http://github.com/bartaz/impress.js/tree/0.2), [zip](http://github.com/bartaz/impress.js/zipball/0.2), [tar](http://github.com/bartaz/impress.js/tarball/0.2))
|
||||
|
||||
|
||||
37
index.html
37
index.html
@@ -280,12 +280,40 @@
|
||||
Last, but not least.
|
||||
|
||||
To make all described above really work, you need to include impress.js in the page.
|
||||
I strongly encourage to minify it first.
|
||||
|
||||
In here I just include full source of the script to make it more readable.
|
||||
|
||||
You also need to call a `impress()` function to initialize impress.js presentation.
|
||||
And you should do it in the end of your document. Not only because it's a good practice, but also
|
||||
because I was lazy, haven't wrapped the code in any kind of "DOM ready" event, so it will not work
|
||||
if included too early in the source ;)
|
||||
because I should be done when the whole document is ready.
|
||||
Of course you can wrap it in any kind of "DOM ready" event, but I was to lazy to do so ;)
|
||||
|
||||
-->
|
||||
<script src="js/impress.js"></script>
|
||||
<script>impress();</script>
|
||||
|
||||
<!--
|
||||
|
||||
The `impress()` function also gives you access to API to control the presentation.
|
||||
|
||||
Just store the result of the call:
|
||||
|
||||
var api = impress();
|
||||
|
||||
and you will get three functions you can call:
|
||||
|
||||
`api.next()` - moves to next step of the presentation,
|
||||
`api.prev()` - moves to previous step of the presentation
|
||||
`api.goto( stepElement ) - moves the presentation to given step element (the DOM element of the step).
|
||||
|
||||
You can also simply call `impress()` again to get the API, so `impress().next()` is also allowed.
|
||||
Don't worry, it wont initialize the presentation again.
|
||||
|
||||
For some example uses of this API check the last part of the source of impress.js where the API
|
||||
is used in event handlers.
|
||||
|
||||
-->
|
||||
|
||||
</body>
|
||||
</html>
|
||||
@@ -328,5 +356,10 @@
|
||||
I'm impressed! Feel free to let me know that you got that far (I'm @bartaz on Twitter), 'cause I'd like
|
||||
to congratulate you personally :)
|
||||
|
||||
But you don't have to do it now. Take my advice and take some time off. Make yourself a cup of coffee, tea,
|
||||
or anything you like to drink. And raise a glass for me ;)
|
||||
|
||||
Cheers!
|
||||
|
||||
-->
|
||||
|
||||
|
||||
422
js/impress.js
422
js/impress.js
@@ -86,7 +86,13 @@
|
||||
|
||||
var scale = function ( s ) {
|
||||
return " scale(" + s + ") ";
|
||||
}
|
||||
};
|
||||
|
||||
var getElementFromUrl = function () {
|
||||
// get id from url # by removing `#` or `#/` from the beginning,
|
||||
// so both "fallback" `#slide-id` and "enhanced" `#/slide-id` will work
|
||||
return byId( window.location.hash.replace(/^#\/?/,"") );
|
||||
};
|
||||
|
||||
// CHECK SUPPORT
|
||||
|
||||
@@ -94,203 +100,242 @@
|
||||
var impressSupported = ( pfx("perspective") != null ) &&
|
||||
( ua.search(/(iphone)|(ipod)|(ipad)|(android)/) == -1 );
|
||||
|
||||
// DOM ELEMENTS
|
||||
var roots = {};
|
||||
|
||||
var impress = byId("impress");
|
||||
var impress = window.impress = function ( rootId ) {
|
||||
|
||||
if (!impressSupported) {
|
||||
impress.className = "impress-not-supported";
|
||||
return;
|
||||
} else {
|
||||
impress.className = "";
|
||||
}
|
||||
rootId = rootId || "impress";
|
||||
|
||||
var canvas = document.createElement("div");
|
||||
canvas.className = "canvas";
|
||||
|
||||
arrayify( impress.childNodes ).forEach(function ( el ) {
|
||||
canvas.appendChild( el );
|
||||
});
|
||||
impress.appendChild(canvas);
|
||||
|
||||
var steps = $$(".step", impress);
|
||||
|
||||
// SETUP
|
||||
// set initial values and defaults
|
||||
|
||||
document.documentElement.style.height = "100%";
|
||||
|
||||
css(document.body, {
|
||||
height: "100%",
|
||||
overflow: "hidden"
|
||||
});
|
||||
|
||||
var props = {
|
||||
position: "absolute",
|
||||
transformOrigin: "top left",
|
||||
transition: "all 0s ease-in-out",
|
||||
transformStyle: "preserve-3d"
|
||||
}
|
||||
|
||||
css(impress, props);
|
||||
css(impress, {
|
||||
top: "50%",
|
||||
left: "50%",
|
||||
perspective: "1000px"
|
||||
});
|
||||
css(canvas, props);
|
||||
|
||||
var current = {
|
||||
translate: { x: 0, y: 0, z: 0 },
|
||||
rotate: { x: 0, y: 0, z: 0 },
|
||||
scale: 1
|
||||
};
|
||||
|
||||
steps.forEach(function ( el, idx ) {
|
||||
var data = el.dataset,
|
||||
step = {
|
||||
translate: {
|
||||
x: data.x || 0,
|
||||
y: data.y || 0,
|
||||
z: data.z || 0
|
||||
},
|
||||
rotate: {
|
||||
x: data.rotateX || 0,
|
||||
y: data.rotateY || 0,
|
||||
z: data.rotateZ || data.rotate || 0
|
||||
},
|
||||
scale: data.scale || 1
|
||||
};
|
||||
|
||||
el.stepData = step;
|
||||
|
||||
if ( !el.id ) {
|
||||
el.id = "step-" + (idx + 1);
|
||||
// if already initialized just return the API
|
||||
if (roots["impress-root-" + rootId]) {
|
||||
return roots["impress-root-" + rootId];
|
||||
}
|
||||
|
||||
css(el, {
|
||||
position: "absolute",
|
||||
transform: "translate(-50%,-50%)" +
|
||||
translate(step.translate) +
|
||||
rotate(step.rotate) +
|
||||
scale(step.scale),
|
||||
transformStyle: "preserve-3d"
|
||||
// DOM ELEMENTS
|
||||
|
||||
var root = byId( rootId );
|
||||
|
||||
if (!impressSupported) {
|
||||
root.className = "impress-not-supported";
|
||||
return;
|
||||
} else {
|
||||
root.className = "";
|
||||
}
|
||||
|
||||
var canvas = document.createElement("div");
|
||||
canvas.className = "canvas";
|
||||
|
||||
arrayify( root.childNodes ).forEach(function ( el ) {
|
||||
canvas.appendChild( el );
|
||||
});
|
||||
root.appendChild(canvas);
|
||||
|
||||
var steps = $$(".step", root);
|
||||
|
||||
// SETUP
|
||||
// set initial values and defaults
|
||||
|
||||
document.documentElement.style.height = "100%";
|
||||
|
||||
css(document.body, {
|
||||
height: "100%",
|
||||
overflow: "hidden"
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
// making given step active
|
||||
|
||||
var active = null;
|
||||
var hashTimeout = null;
|
||||
|
||||
var select = function ( el ) {
|
||||
if ( !el || !el.stepData || el == active) {
|
||||
// selected element is not defined as step or is already active
|
||||
return false;
|
||||
var props = {
|
||||
position: "absolute",
|
||||
transformOrigin: "top left",
|
||||
transition: "all 0s ease-in-out",
|
||||
transformStyle: "preserve-3d"
|
||||
}
|
||||
|
||||
// Sometimes it's possible to trigger focus on first link with some keyboard action.
|
||||
// Browser in such a case tries to scroll the page to make this element visible
|
||||
// (even that body overflow is set to hidden) and it breaks our careful positioning.
|
||||
//
|
||||
// So, as a lousy (and lazy) workaround we will make the page scroll back to the top
|
||||
// whenever slide is selected
|
||||
//
|
||||
// If you are reading this and know any better way to handle it, I'll be glad to hear about it!
|
||||
window.scrollTo(0, 0);
|
||||
css(root, props);
|
||||
css(root, {
|
||||
top: "50%",
|
||||
left: "50%",
|
||||
perspective: "1000px"
|
||||
});
|
||||
css(canvas, props);
|
||||
|
||||
var step = el.stepData;
|
||||
|
||||
if ( active ) {
|
||||
active.classList.remove("active");
|
||||
}
|
||||
el.classList.add("active");
|
||||
|
||||
impress.className = "step-" + el.id;
|
||||
|
||||
// `#/step-id` is used instead of `#step-id` to prevent default browser
|
||||
// scrolling to element in hash
|
||||
//
|
||||
// and it has to be set after animation finishes, because in chrome it
|
||||
// causes transtion being laggy
|
||||
window.clearTimeout( hashTimeout );
|
||||
hashTimeout = window.setTimeout(function () {
|
||||
window.location.hash = "#/" + el.id;
|
||||
}, 1000);
|
||||
|
||||
var target = {
|
||||
rotate: {
|
||||
x: -parseInt(step.rotate.x, 10),
|
||||
y: -parseInt(step.rotate.y, 10),
|
||||
z: -parseInt(step.rotate.z, 10)
|
||||
},
|
||||
translate: {
|
||||
x: -step.translate.x,
|
||||
y: -step.translate.y,
|
||||
z: -step.translate.z
|
||||
},
|
||||
scale: 1 / parseFloat(step.scale)
|
||||
var current = {
|
||||
translate: { x: 0, y: 0, z: 0 },
|
||||
rotate: { x: 0, y: 0, z: 0 },
|
||||
scale: 1
|
||||
};
|
||||
|
||||
// check if the transition is zooming in or not
|
||||
var zoomin = target.scale >= current.scale;
|
||||
var stepData = {};
|
||||
|
||||
// if presentation starts (nothing is active yet)
|
||||
// don't animate (set duration to 0)
|
||||
var duration = (active) ? "1s" : "0";
|
||||
var isStep = function ( el ) {
|
||||
return !!(el && el.id && stepData["impress-" + el.id]);
|
||||
}
|
||||
|
||||
steps.forEach(function ( el, idx ) {
|
||||
var data = el.dataset,
|
||||
step = {
|
||||
translate: {
|
||||
x: data.x || 0,
|
||||
y: data.y || 0,
|
||||
z: data.z || 0
|
||||
},
|
||||
rotate: {
|
||||
x: data.rotateX || 0,
|
||||
y: data.rotateY || 0,
|
||||
z: data.rotateZ || data.rotate || 0
|
||||
},
|
||||
scale: data.scale || 1,
|
||||
el: el
|
||||
};
|
||||
|
||||
if ( !el.id ) {
|
||||
el.id = "step-" + (idx + 1);
|
||||
}
|
||||
|
||||
stepData["impress-" + el.id] = step;
|
||||
|
||||
css(el, {
|
||||
position: "absolute",
|
||||
transform: "translate(-50%,-50%)" +
|
||||
translate(step.translate) +
|
||||
rotate(step.rotate) +
|
||||
scale(step.scale),
|
||||
transformStyle: "preserve-3d"
|
||||
});
|
||||
|
||||
css(impress, {
|
||||
// to keep the perspective look similar for different scales
|
||||
// we need to 'scale' the perspective, too
|
||||
perspective: step.scale * 1000 + "px",
|
||||
transform: scale(target.scale),
|
||||
transitionDuration: duration,
|
||||
transitionDelay: (zoomin ? "500ms" : "0ms")
|
||||
});
|
||||
|
||||
css(canvas, {
|
||||
transform: rotate(target.rotate, true) + translate(target.translate),
|
||||
transitionDuration: duration,
|
||||
transitionDelay: (zoomin ? "0ms" : "500ms")
|
||||
// making given step active
|
||||
|
||||
var active = null;
|
||||
var hashTimeout = null;
|
||||
|
||||
var goto = function ( el ) {
|
||||
if ( !isStep(el) || el == active) {
|
||||
// selected element is not defined as step or is already active
|
||||
return false;
|
||||
}
|
||||
|
||||
// Sometimes it's possible to trigger focus on first link with some keyboard action.
|
||||
// Browser in such a case tries to scroll the page to make this element visible
|
||||
// (even that body overflow is set to hidden) and it breaks our careful positioning.
|
||||
//
|
||||
// So, as a lousy (and lazy) workaround we will make the page scroll back to the top
|
||||
// whenever slide is selected
|
||||
//
|
||||
// If you are reading this and know any better way to handle it, I'll be glad to hear about it!
|
||||
window.scrollTo(0, 0);
|
||||
|
||||
var step = stepData["impress-" + el.id];
|
||||
|
||||
if ( active ) {
|
||||
active.classList.remove("active");
|
||||
}
|
||||
el.classList.add("active");
|
||||
|
||||
root.className = "step-" + el.id;
|
||||
|
||||
// `#/step-id` is used instead of `#step-id` to prevent default browser
|
||||
// scrolling to element in hash
|
||||
//
|
||||
// and it has to be set after animation finishes, because in chrome it
|
||||
// causes transtion being laggy
|
||||
window.clearTimeout( hashTimeout );
|
||||
hashTimeout = window.setTimeout(function () {
|
||||
window.location.hash = "#/" + el.id;
|
||||
}, 1000);
|
||||
|
||||
var target = {
|
||||
rotate: {
|
||||
x: -parseInt(step.rotate.x, 10),
|
||||
y: -parseInt(step.rotate.y, 10),
|
||||
z: -parseInt(step.rotate.z, 10)
|
||||
},
|
||||
translate: {
|
||||
x: -step.translate.x,
|
||||
y: -step.translate.y,
|
||||
z: -step.translate.z
|
||||
},
|
||||
scale: 1 / parseFloat(step.scale)
|
||||
};
|
||||
|
||||
// check if the transition is zooming in or not
|
||||
var zoomin = target.scale >= current.scale;
|
||||
|
||||
// if presentation starts (nothing is active yet)
|
||||
// don't animate (set duration to 0)
|
||||
var duration = (active) ? "1s" : "0";
|
||||
|
||||
css(root, {
|
||||
// to keep the perspective look similar for different scales
|
||||
// we need to 'scale' the perspective, too
|
||||
perspective: step.scale * 1000 + "px",
|
||||
transform: scale(target.scale),
|
||||
transitionDuration: duration,
|
||||
transitionDelay: (zoomin ? "500ms" : "0ms")
|
||||
});
|
||||
|
||||
css(canvas, {
|
||||
transform: rotate(target.rotate, true) + translate(target.translate),
|
||||
transitionDuration: duration,
|
||||
transitionDelay: (zoomin ? "0ms" : "500ms")
|
||||
});
|
||||
|
||||
current = target;
|
||||
active = el;
|
||||
|
||||
return el;
|
||||
};
|
||||
|
||||
var prev = function () {
|
||||
var prev = steps.indexOf( active ) - 1;
|
||||
prev = prev >= 0 ? steps[ prev ] : steps[ steps.length-1 ];
|
||||
|
||||
return goto(prev);
|
||||
};
|
||||
|
||||
var next = function () {
|
||||
var next = steps.indexOf( active ) + 1;
|
||||
next = next < steps.length ? steps[ next ] : steps[ 0 ];
|
||||
|
||||
return goto(next);
|
||||
};
|
||||
|
||||
window.addEventListener("hashchange", function () {
|
||||
goto( getElementFromUrl() );
|
||||
}, false);
|
||||
|
||||
// START
|
||||
// by selecting step defined in url or first step of the presentation
|
||||
goto(getElementFromUrl() || steps[0]);
|
||||
|
||||
return (roots[ "impress-root-" + rootId ] = {
|
||||
goto: goto,
|
||||
next: next,
|
||||
prev: prev
|
||||
});
|
||||
|
||||
current = target;
|
||||
active = el;
|
||||
}
|
||||
})(document, window);
|
||||
|
||||
return el;
|
||||
};
|
||||
// EVENTS
|
||||
|
||||
var selectPrev = function () {
|
||||
var prev = steps.indexOf( active ) - 1;
|
||||
prev = prev >= 0 ? steps[ prev ] : steps[ steps.length-1 ];
|
||||
|
||||
return select(prev);
|
||||
};
|
||||
|
||||
var selectNext = function () {
|
||||
var next = steps.indexOf( active ) + 1;
|
||||
next = next < steps.length ? steps[ next ] : steps[ 0 ];
|
||||
|
||||
return select(next);
|
||||
};
|
||||
|
||||
// EVENTS
|
||||
(function ( document, window ) {
|
||||
'use strict';
|
||||
|
||||
// keyboard navigation handler
|
||||
document.addEventListener("keydown", function ( event ) {
|
||||
if ( event.keyCode == 9 || ( event.keyCode >= 32 && event.keyCode <= 34 ) || (event.keyCode >= 37 && event.keyCode <= 40) ) {
|
||||
switch( event.keyCode ) {
|
||||
case 33: ; // pg up
|
||||
case 37: ; // left
|
||||
case 38: // up
|
||||
selectPrev();
|
||||
impress().prev();
|
||||
break;
|
||||
case 9: ; // tab
|
||||
case 32: ; // space
|
||||
case 34: ; // pg down
|
||||
case 39: ; // right
|
||||
case 40: // down
|
||||
selectNext();
|
||||
impress().next();
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -298,12 +343,12 @@
|
||||
}
|
||||
}, false);
|
||||
|
||||
// delegated handler for clicking on the links to presentation steps
|
||||
document.addEventListener("click", function ( event ) {
|
||||
// event delegation with "bubbling"
|
||||
// check if event target (or any of its parents is a link or a step)
|
||||
// check if event target (or any of its parents is a link)
|
||||
var target = event.target;
|
||||
while ( (target.tagName != "A") &&
|
||||
(!target.stepData) &&
|
||||
(target != document.body) ) {
|
||||
target = target.parentNode;
|
||||
}
|
||||
@@ -313,28 +358,47 @@
|
||||
|
||||
// if it's a link to presentation step, target this step
|
||||
if ( href && href[0] == '#' ) {
|
||||
target = byId( href.slice(1) );
|
||||
target = document.getElementById( href.slice(1) );
|
||||
}
|
||||
}
|
||||
|
||||
if ( select(target) ) {
|
||||
if ( impress().goto(target) ) {
|
||||
event.stopImmediatePropagation();
|
||||
event.preventDefault();
|
||||
}
|
||||
}, false);
|
||||
|
||||
var getElementFromUrl = function () {
|
||||
// get id from url # by removing `#` or `#/` from the beginning,
|
||||
// so both "fallback" `#slide-id` and "enhanced" `#/slide-id` will work
|
||||
return byId( window.location.hash.replace(/^#\/?/,"") );
|
||||
}
|
||||
// delegated handler for clicking on step elements
|
||||
document.addEventListener("click", function ( event ) {
|
||||
var target = event.target;
|
||||
// find closest step element
|
||||
while ( !target.classList.contains("step") &&
|
||||
(target != document.body) ) {
|
||||
target = target.parentNode;
|
||||
}
|
||||
|
||||
window.addEventListener("hashchange", function () {
|
||||
select( getElementFromUrl() );
|
||||
if ( impress().goto(target) ) {
|
||||
event.preventDefault();
|
||||
}
|
||||
}, false);
|
||||
|
||||
// START
|
||||
// by selecting step defined in url or first step of the presentation
|
||||
select(getElementFromUrl() || steps[0]);
|
||||
// touch handler to detect taps on the left and right side of the screen
|
||||
document.addEventListener("touchstart", function ( event ) {
|
||||
if (event.touches.length === 1) {
|
||||
var x = event.touches[0].clientX,
|
||||
width = window.innerWidth * 0.3,
|
||||
result = null;
|
||||
|
||||
if ( x < width ) {
|
||||
result = impress().prev();
|
||||
} else if ( x > window.innerWidth - width ) {
|
||||
result = impress().next();
|
||||
}
|
||||
|
||||
if (result) {
|
||||
event.preventDefault();
|
||||
}
|
||||
}
|
||||
}, false);
|
||||
})(document, window);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user