Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

ok, this is better

  • Loading branch information...
commit f5bd676af5ef0d494c03218d90885f2bf5967963 1 parent 60eb76a
@naugtur authored
Showing with 385 additions and 142 deletions.
  1. +27 −0 README.md
  2. +155 −108 index.html
  3. +154 −0 js/builder.js
  4. +49 −34 js/impress.js
View
27 README.md
@@ -0,0 +1,27 @@
+builder4impress
+==============
+A tool that builds impress.js presentations
+
+
+Current usage instructions
+---------
+
+First - skip one slide back (left arrow) to get to the overview. [I currently scale the movements assuming you are there]
+
+Hover over a slide and a control should show. Dragging the "M" letter will move the slide around, dragging "R" horizontally will rotate and dragging "S" vertically will scale.
+
+
+
+Plans and issues [notes to self, but tips are appreciated ;)]
+---------
+
+find a way to position the controls better,
+enable adding new slides,
+automatically load the overview slide (create it?),
+and obviously some simple content editing
+
+
+License
+---------
+MIT License
+
View
263 index.html
@@ -1,4 +1,49 @@
<!doctype html>
+
+<!--
+
+ Welcome to the light side of the source, young padawan.
+
+ One step closer to learn something interesting you are...
+
+ ____
+ _.' : `._
+ .-.'`. ; .'`.-.
+ __ / : ___\ ; /___ ; \ __
+ ,'_ ""--.:__;".-.";: :".-.":__;.--"" _`,
+ :' `.t""--.. '<@.`;_ ',@>` ..--""j.' `;
+ `:-.._J '-.-'L__ `-- ' L_..-;'
+ "-.__ ; .-" "-. : __.-"
+ L ' /.------.\ ' J
+ "-. "--" .-"
+ __.l"-:_JL_;-";.__
+ .-j/'.; ;"""" / .'\"-.
+ .' /:`. "-.: .-" .'; `.
+ .-" / ; "-. "-..-" .-" : "-.
+ .+"-. : : "-.__.-" ;-._ \
+ ; \ `.; ; : : "+. ;
+ : ; ; ; : ; : \:
+ ; : ; : ;: ; :
+ : \ ; : ; : ; / ::
+ ; ; : ; : ; : ;:
+ : : ; : ; : : ; : ;
+ ;\ : ; : ; ; ; ;
+ : `."-; : ; : ; / ;
+ ; -: ; : ; : .-" :
+ :\ \ : ; : \.-" :
+ ;`. \ ; : ;.'_..-- / ;
+ : "-. "-: ; :/." .' :
+ \ \ : ;/ __ :
+ \ .-`.\ /t-"" ":-+. :
+ `. .-" `l __/ /`. : ; ; \ ;
+ \ .-" .-"-.-" .' .'j \ / ;/
+ \ / .-" /. .'.' ;_:' ;
+ :-""-.`./-.' / `.___.'
+ \ `t ._ /
+ "-.t-._:'
+
+-->
+
<html lang="en">
<head>
<meta charset="utf-8" />
@@ -9,38 +54,67 @@
<link href="http://fonts.googleapis.com/css?family=Open+Sans:regular,semibold,italic,italicsemibold|PT+Sans:400,700,400italic,700italic|PT+Serif:400,700,400italic,700italic" rel="stylesheet" />
+ <!--
+ Impress.js doesn't depend on any external stylesheet. Script adds all styles it needs for
+ presentation to work.
+
+ This style below contains styles only for demo presentation. Browse it to see how impress.js
+ classes are used to style presentation steps, or how to apply fallback styles, but I don't want
+ you to use them directly in your presentation.
+
+ Be creative, build your own. We don't really want all impress.js presentations to look the same,
+ don't we?
+
+ When creating your own presentation get rid of this file. Start from scratch, it's fun!
+ -->
<link href="css/impress-demo.css" rel="stylesheet" />
</head>
<body>
-<div id="impress" class="impress-not-supported">
-
- <div id="beforeedit" class="step slide" data-x="-2000" data-y="-1500">
- <strong>This is a proof of concept position editor for impress.js</strong>
- <p>mousedown on a slide to start editing its position</p>
- <p>when editing use WSAD to move the slide</p>
- <p>Q and E rotate</p>
- <p>Z and X scale</p>
- <strong>use an overview to edit</strong>
- <p>go to next slide - it's an overwiew for editing</p>
- <strong>saving data</strong>
- <p>your changes are not saved yet, but it won't be hard - take a look at document.getElementById('impress').innerHTML</p>
-
- </div>
+<!--
- <div id="edit" class="step" data-x="3000" data-y="1500" data-scale="20">
- </div>
+ That's the wrapper for your presentation steps. In this element all the impress.js magic happens.
+ It doesn't have to be a `<div>`. Only `id` is important here as that's how the script find it.
+ It's worth to notice the `impress-not-supported` class. This class means, that browser doesn't
+ support features required by impress.js, so you can apply some fallback styles in your CSS.
+ It's not necessary to add it manually on this element. If the script detects that browser is not
+ good enough it will add this class, but keeping it in HTML means that users without JavaScript
+ will also get fallback styles.
+-->
+<div id="impress" class="impress-not-supported">
+
<div class="fallback-message">
<p>Your browser <b>doesn't support the features required</b> by impress.js, so you are presented with a simplified version of this presentation.</p>
<p>For the best experience please use the latest <b>Chrome</b> or <b>Safari</b> browser. Firefox 10 (to be released soon) will also handle it.</p>
</div>
+ <!--
+ Here is where interesting thing start to happen.
+
+ Each step of the presentation should be an element inside the `#impress` with a class name
+ of `step`. These step elements are positioned, rotated and scaled by impress.js, and
+ the 'camera' shows them on each step of the presentation.
+
+ Positioning information is passed through data attributes.
+
+ In the example below we only specify x and y position of the step element with `data-x="-1000"`
+ and `data-y="-1500` attributes. This means that **the center** of the element (yes, the center)
+ will be positioned in point x = -1000px and y = -1500px of the presentation 'canvas'.
+
+ It will not be rotated or scaled.
+ -->
<div id="bored" class="step slide" data-x="-1000" data-y="-1500">
<q>Aren't you just <b>bored</b> with all those slides-based presentations?</q>
</div>
+ <!--
+ The `id` attribute of the step element is used to identify it in the URL, but it's optional.
+ If it is not defined, it will get a default value of `step-N` where N is a number of slide.
+
+ So in the example below it'll be `step-2`.
+ -->
<div class="step slide" data-x="0" data-y="-1500">
<q>Don't you think that presentations given <strong>in modern browsers</strong> shouldn't <strong>copy the limits</strong> of 'classic' slide decks?</q>
</div>
@@ -49,12 +123,26 @@
<q>Would you like to <strong>impress your audience</strong> with <strong>stunning visualization</strong> of your talk?</q>
</div>
+ <!--
+ This is an example of step element being scaled.
+
+ Again, we use a `data-` attribute, this time it's `data-scale="4"`, so it means that this
+ element will be 4 times larger than the others.
+ From presentation and transitions point of view it means, that it will have to be scaled
+ down (4 times) to make it back to it's correct size.
+ -->
<div id="title" class="step" data-x="0" data-y="0" data-scale="4">
<span class="try">then you should try</span>
<h1>impress.js<sup>*</sup></h1>
<span class="footnote"><sup>*</sup> no rhyme intended</span>
</div>
+ <!--
+ This element introduces rotation.
+
+ Notation shouldn't be a surprise. We use `data-rotate="90"` attribute, meaning that this
+ element should be rotated by 90 degrees clockwise.
+ -->
<div id="its" class="step" data-x="850" data-y="3000" data-rotate="90" data-scale="5">
<p>It's a <strong>presentation tool</strong> <br/>
inspired by the idea behind <a href="http://prezi.com">prezi.com</a> <br/>
@@ -65,6 +153,13 @@
<p>visualize your <b>big</b> <span class="thoughts">thoughts</span></p>
</div>
+ <!--
+ And now it gets really exiting! We move into third dimension!
+
+ Along with `data-x` and `data-y`, you can define the position on third (Z) axis, with
+ `data-z`. In the example below we use `data-z="-3000"` meaning that element should be
+ positioned far away from us (by 3000px).
+ -->
<div id="tiny" class="step" data-x="2825" data-y="2325" data-z="-3000" data-rotate="300" data-scale="1">
<p>and <b>tiny</b> ideas</p>
</div>
@@ -86,115 +181,67 @@
<p>one more thing...</p>
</div>
+ <!--
+ And the last one shows full power and flexibility of impress.js.
+
+ You can not only position element in 3D, but also rotate it around any axis.
+ So this one here will get rotated by -40 degrees (40 degrees anticlockwise) around X axis and
+ 10 degrees (clockwise) around Y axis.
+
+ You can of course rotate it around Z axis with `data-rotate-z` - it has exactly the same effect
+ as `data-rotate` (these two are basically aliases).
+ -->
<div id="its-in-3d" class="step" data-x="6200" data-y="4300" data-z="-100" data-rotate-x="-40" data-rotate-y="10" data-scale="2">
<p><span class="have">have</span> <span class="you">you</span> <span class="noticed">noticed</span> <span class="its">it's</span> <span class="in">in</span> <b>3D<sup>*</sup></b>?</p>
<span class="footnote">* beat that, prezi ;)</span>
</div>
+ <!--
+ So to make a summary of all the possible attributes used to position presentation steps, we have:
+
+ * `data-x`, `data-y`, `data-z` -- they define the position of **the center** of step element on
+ the canvas in pixels; their default value is 0;
+ * `data-rotate-x`, `data-rotate-y`, 'data-rotate-z`, `data-rotate` -- they define the rotation of
+ the element around given axis in degrees; their default value is 0; `data-rotate` and `data-rotate-z`
+ are exactly the same;
+ * `data-scale` -- defines the scale of step element; default value is 1
+ -->
<div id="overview" class="step" data-x="3000" data-y="1500" data-scale="10">
</div>
</div>
+<!--
+ Hint is not related to impress.js in any way.
+
+ But it can show you how to use impress.js features in creative way.
+
+ When the presentation step is shown (selected) it's element get's the class of "active" and `#impress` root
+ element get's the class based on active step id `step-ID` (where ID is the step id)... It probably is not
+ so clear because of all these IDs in here, so for example when the first step (the one with id of `bored`)
+ is active, `#impress` element get a class of `step-bored`.
+
+ This class is used by this hint below. Check CSS file to see how it's shown with delayed CSS animation.
+-->
<div class="hint">
<p>Use a spacebar or arrow keys to navigate</p>
</div>
+
+<!--
+ Last, but not least.
+
+ To make all described above really work, you need to include impress.js in the page.
+ 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 ;)
+-->
<script src="js/impress.js"></script>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js"></script>
+<script src="js/builder.js"></script>
<script>
-
-//Proof of concept editor for bartaz's impress.js
-// by naugtur
-// MIT License if anybody asked
-$(function(){
- var state={
- editing:false,
- node:false,
- data:{
- x:0,
- y:0,
- rotate:0,
- scale:0
- }
- },
- config={
- rotateStep:3,
- scaleStep:1,
- moveStep:50
- },
- defaults={
- x:0,
- y:0,
- rotate:0,
- scale:1
- };
- $('body').on('mousedown','.step',function(e){
- state.editing=true;
- state.node=$(this);
- state.node.fadeTo(0.6);
- });
- $('body').on('mouseup','.step',function(e){
- state.editing=false;
- var $t=$(this);
- $t.fadeTo(1);
- });
-
- $('body').on('keypress',function(e){
- if(state.editing){
- var $t=state.node;
- for(var i in state.data){
- var tmp=$t.attr('data-'+i);
- if(tmp===''){tmp=defaults[i]}
- state.data[i]= ~~(tmp);
- }
- //console.log(['before...',state.data,state.node[0]]);
-
- switch(e.which){
- case 113: //q
- state.data.rotate-=config.rotateStep;
- break;
- case 119: //w
- state.data.y-=config.moveStep;
- break;
- case 101: //e
- state.data.rotate+=config.rotateStep;
- break;
- case 97: //a
- state.data.x-=config.moveStep;
- break;
- case 115: //s
- state.data.y+=config.moveStep;
- break;
- case 100: //d
- state.data.x+=config.moveStep;
- break;
- case 122: //z
- state.data.scale+=config.scaleStep;
- break;
- case 120: //x
- state.data.scale-=config.scaleStep;
- break;
-
- default:
- console.log(e.which);
-
- //yeah, I know, but it looks better when it's here
- break;
-
-
- }
- //console.log(['done...',state.data,state.node[0]]);
- //reapply all. damn slow
- for(var i in state.data){
- $t.attr('data-'+i,state.data[i]);
- }
-
- window['--drawSlideGlobalHandler'](state.node[0],'whatever')
-
- }
- });
-
+Builder.init({
+ redrawFunction:window['--drawSlideGlobalHandler'] //pass an API method here when it emerges
});
</script>
View
154 js/builder.js
@@ -0,0 +1,154 @@
+Builder=(function(){
+ var state={
+ editing:false,
+ $node:false,
+ data:{
+ x:0,
+ y:0,
+ rotate:0,
+ scale:0
+ }
+ },
+ config={
+ rotateStep:1,
+ scaleStep:0.1,
+ moveStep:10,
+ redrawFunction:false
+ },
+ defaults={
+ x:0,
+ y:0,
+ rotate:0,
+ scale:1
+ },
+ mouse={
+ prevX:false,
+ prevY:false,
+ activeFunction:false
+ },
+ handlers={},
+ redrawTimeout,
+ $controls,$overview;
+
+ handlers.move=function(x,y){
+ console.log(x,state.data.x);
+ state.data.x= ~~(state.data.x)+x*config.moveStep;
+ state.data.y= ~~(state.data.y)+y*config.moveStep;
+ };
+ handlers.scale=function(x,y){
+ state.data.scale-= -y * config.scaleStep;
+ };
+ handlers.rotate=function(x){
+ console.log(state.rotate);
+ state.data.rotate-= -x*config.rotateStep;
+ };
+
+
+ function init(conf){
+ config=$.extend(config,conf);
+
+ $controls=$('<div></div>').hide().css({
+ padding:'5px',
+ background: '#222',
+ color: '#fff',
+ width: '40px',
+ 'text-align': 'center'
+ });
+
+ $('<div></div>').text('M').data('func','move').appendTo($controls);
+ $('<div></div>').text('R').data('func','rotate').appendTo($controls);
+ $('<div></div>').text('S').data('func','scale').appendTo($controls);
+
+ $controls.appendTo('body').on('mousedown','div',function(e){
+ e.preventDefault();
+ mouse.activeFunction=handlers[$(this).data('func')];
+ loadData();
+ mouse.prevX=e.pageX;
+ mouse.prevY=e.pageY;
+ $(document).on('mousemove.handler1',handleMouseMove);
+ return false;
+ });
+ $(document).on('mouseup',function(){
+ mouse.activeFunction=false;
+ $(document).off('mousemove.handler1');
+ });
+
+ $('body').on('mouseenter','.step',function(){
+ if(!mouse.activeFunction){
+ //show controls
+ state.$node=$(this);
+ showControls(state.$node);
+ }
+ });
+
+ /*
+ $overview=$('<div></div>').attr({id:'builderOverAll','class':'step','data-x':"3000", 'data-y':"1500", 'data-scale':"10"}).prependTo('#impress');
+ config.redrawFunction($overview[0]);
+ //this doesnt seem to work. I'll have to update impress to a version that has API already
+ $overview.trigger('click');
+ */
+
+ }
+
+ function showControls($where){
+ var pos=$where.offset();
+
+ $controls.offset({top:pos.top+1,left:pos.left+1}).show();
+ //$controls.prependTo(where).show();
+ }
+
+
+ function loadData(){
+ console.log('load',state.$node[0].dataset.x);
+ //state.data=state.$node[0].dataset;
+ //add defaults
+
+
+ state.data.x=state.$node[0].dataset.x || defaults.x;
+ state.data.y=state.$node[0].dataset.y || defaults.y;
+ state.data.scale=state.$node[0].dataset.scale || defaults.scale;
+ state.data.rotate=state.$node[0].dataset.rotate || defaults.rotate;
+
+ }
+
+ function redraw(){
+ clearTimeout(redrawTimeout);
+ redrawTimeout=setTimeout(function(){
+ //state.$node[0].dataset=state.data;
+
+ state.$node[0].dataset.scale=state.data.scale;
+ state.$node[0].dataset.rotate=state.data.rotate;
+ state.$node[0].dataset.x=state.data.x;
+ state.$node[0].dataset.y=state.data.y;
+ /**/
+ console.log(state.data,state.$node[0].dataset,state.$node[0].dataset===state.data);
+
+ config.redrawFunction(state.$node[0]);
+ showControls(state.$node);
+ //console.log(['redrawn',state.$node[0].dataset]);
+ },50);
+ }
+
+ function handleMouseMove(e){
+ e.preventDefault();
+ e.stopPropagation();
+
+
+ var x=e.pageX-mouse.prevX,
+ y=e.pageY-mouse.prevY;
+
+ mouse.prevX=e.pageX;
+ mouse.prevY=e.pageY;
+ if(mouse.activeFunction){
+ mouse.activeFunction(x,y);
+ redraw();
+ }
+
+ return false;
+ }
+
+ return {
+ init:init
+ };
+
+})();
View
83 js/impress.js
@@ -84,7 +84,7 @@
};
var scale = function ( s ) {
- return " scaleX(" + s.x + ") scaleY(" + s.y + ") scaleZ(" + s.z + ") ";
+ return " scale(" + s + ") ";
}
// CHECK SUPPORT
@@ -127,7 +127,7 @@
var props = {
position: "absolute",
transformOrigin: "top left",
- transition: "all 1s ease-in-out",
+ transition: "all 0s ease-in-out",
transformStyle: "preserve-3d"
}
@@ -142,10 +142,11 @@
var current = {
translate: { x: 0, y: 0, z: 0 },
rotate: { x: 0, y: 0, z: 0 },
- scale: { x: 1, y: 1, z: 1 }
+ scale: 1
};
- var drawSlide=function ( el, idx ) {
+
+ var doSlide=function ( el, idx ) {
var data = el.dataset,
step = {
translate: {
@@ -158,11 +159,7 @@
y: data.rotateY || 0,
z: data.rotateZ || data.rotate || 0
},
- scale: {
- x: data.scaleX || data.scale || 1,
- y: data.scaleY || data.scale || 1,
- z: data.scaleZ || 1
- }
+ scale: data.scale || 1
};
el.stepData = step;
@@ -180,20 +177,20 @@
transformStyle: "preserve-3d"
});
- }
+ };
- //all API I needed. This should not work like that I guess ;)
- window['--drawSlideGlobalHandler']=drawSlide;
+ steps.forEach(doSlide);
+ window['--drawSlideGlobalHandler']=doSlide;
- steps.forEach(drawSlide);
// making given step active
var active = null;
+ var hashTimeout = null;
var select = function ( el ) {
- if ( !el || !el.stepData ) {
- // selected element is not defined as step
+ if ( !el || !el.stepData || el == active) {
+ // selected element is not defined as step or is already active
return false;
}
@@ -218,7 +215,13 @@
// `#/step-id` is used instead of `#step-id` to prevent default browser
// scrolling to element in hash
- window.location.hash = "#/" + el.id;
+ //
+ // 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: {
@@ -226,30 +229,33 @@
y: -parseInt(step.rotate.y, 10),
z: -parseInt(step.rotate.z, 10)
},
- scale: {
- x: 1 / parseFloat(step.scale.x),
- y: 1 / parseFloat(step.scale.y),
- z: 1 / parseFloat(step.scale.z)
- },
translate: {
x: -step.translate.x,
y: -step.translate.y,
z: -step.translate.z
- }
+ },
+ scale: 1 / parseFloat(step.scale)
};
- var zoomin = target.scale.x >= current.scale.x;
+ // 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(impress, {
// to keep the perspective look similar for different scales
// we need to 'scale' the perspective, too
- perspective: step.scale.x * 1000 + "px",
+ 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")
});
@@ -257,32 +263,41 @@
active = el;
return el;
- }
+ };
+
+ 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
document.addEventListener("keydown", function ( event ) {
if ( event.keyCode == 9 || ( event.keyCode >= 32 && event.keyCode <= 34 ) || (event.keyCode >= 37 && event.keyCode <= 40) ) {
- var next = active;
switch( event.keyCode ) {
case 33: ; // pg up
case 37: ; // left
case 38: // up
- next = steps.indexOf( active ) - 1;
- next = next >= 0 ? steps[ next ] : steps[ steps.length-1 ];
+ selectPrev();
break;
case 9: ; // tab
case 32: ; // space
case 34: ; // pg down
case 39: ; // right
case 40: // down
- next = steps.indexOf( active ) + 1;
- next = next < steps.length ? steps[ next ] : steps[ 0 ];
- break;
+ selectNext();
+ break;
}
- select(next);
-
event.preventDefault();
}
}, false);
@@ -309,7 +324,7 @@
if ( select(target) ) {
event.preventDefault();
}
- });
+ }, false);
var getElementFromUrl = function () {
// get id from url # by removing `#` or `#/` from the beginning,
Please sign in to comment.
Something went wrong with that request. Please try again.