The relative position in rel plugin is currently based on the world coordinate. So for the same effect, like fly in from the right-hand side, we must use different `data-rel-x/y/z` value. Why not let the plugin do the hard part? So I introduce a `data-rel-position`, when set to `relative`, all relative attribute is based on the position and rotation of previous slide. So no matter the rotation of previous slide, data-rel-x="1000" always looks like fly in from the right-hand side. We can change the position and rotation of one slide, and the position of all following slides will be changed too. When `data-rel-position` is set to `relative`, relative rotation has a clear meaning. It describes the relative rotations between slides. We don't need to set rotations for all slide, setting the key slides is enough. If `data-rel-position` is not relative, the effect of `data-rel-rotate-x/y/z` is not clear, so they're only used when `data-rel-position="relative"`. After the introduction of relative rotation, there're 6 attribute that will inherit from previous slide. If we want to set a relative X move, we have to set all other 5 attributes to 0. It's boring. So a `data-rel-clear` is used to set all 6 attributes to 0, and then the value specified in current slide is applied. The `examples/3D-positions/index.html` shows some usage. As you can see, the html code of two slide ring is the same, and slides except for the first two in a ring has no position attributes. It work by inheriting the previous one. This PR invokes a lot math calculations. Basically, the rotation of a slide is translated into the coordinate describing the directions of X/Y/Z axes. And `data-rel-x/y/z` can be easily calculated by that. The rotations is the hard part, I mainly use the algorithm in the Quaternions and spatial rotation - Wikipedia to compose two and more rotations. I'm not a math guy, hope I don't make much mistakes.
Impress.js Libraries
The src/lib/*.js files contain library functions. The main difference to plugins is that:
- Libraries are closer to the impress.js core than plugins (arguably a subjective metric)
- Libraries are common utility functions used by many plugins
- Libraries are called synchronously, which is why the event based paradigm that plugins use to communicate isn't useful.
Plugins can access libraries via the API:
var api;
document.addEventListener( "impress:init", function(event){
api = event.detail.api;
api().lib.<libraryName>.<libaryFunction>();
});
...which is equivalent to:
impress().lib.<libraryName>.<libraryFunction>();
Implementing a library
-
Create a file under
src/lib/. -
Start with the standard boilerplate documentation, and the (function(document, window){})(); wrapper.
-
The library should implement a factory function, and make its existence known to impress.js core:
window.impress.addLibraryFactory( { libName : libraryFactory} );
-
The library function should return a similar API object as core
impress()function does:var libraryFactory = function(rootId) { /* implement library functions ... */
var lib = { libFunction1: libFunction1, libFunction2: libFunction2 } return lib;};
-
While rarely used, impress.js actually supports multiple presentation root div elements on a single html page. Each of these have their own API object, identified by the root element id attribute:
impress("other-root-id").init();
(The default rootId obviously is "impress".)
Libraries MUST implement this support for multiple root elements as well.
- impress.js core will call the factory once for each separate root element being initialized via
impress.init(rootId). - Any state that a library might hold, MUST be stored per
rootId. - Note that as we now support also
impress(rootId).tear(), the same root element might be initialized more than once, and each of these MUST be treated as a new valid initialization.
Putting all of the above together, a skeleton library file will look like:
/**
* Example library libName
*
* Henrik Ingo (c) 2016
* MIT License
*/
(function ( document, window ) {
'use strict';
// Singleton library variables
var roots = [];
var singletonVar = {};
var libraryFactory = function(rootId) {
if (roots["impress-root-" + rootId]) {
return roots["impress-root-" + rootId];
}
// Per root global variables (instance variables?)
var instanceVar = {};
// LIBRARY FUNCTIONS
var libraryFunction1 = function () {
/* ... */
};
var libraryFunction2 = function () {
/* ... */
};
var lib = {
libFunction1: libFunction1,
libFunction2: libFunction2
}
roots["impress-root-" + rootId] = lib;
return lib;
};
// Let impress core know about the existence of this library
window.impress.addLibraryFactory( { libName : libraryFactory } );
})(document, window);