Add relative move and rotate to rel plugin (#794)
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.
This commit is contained in:
620
js/impress.js
620
js/impress.js
@@ -1297,6 +1297,436 @@
|
||||
|
||||
} )( document, window );
|
||||
|
||||
/**
|
||||
* Helper functions for rotation.
|
||||
*
|
||||
* Tommy Tam (c) 2021
|
||||
* MIT License
|
||||
*/
|
||||
( function( document, window ) {
|
||||
"use strict";
|
||||
|
||||
// Singleton library variables
|
||||
var roots = [];
|
||||
|
||||
var libraryFactory = function( rootId ) {
|
||||
if ( roots[ "impress-root-" + rootId ] ) {
|
||||
return roots[ "impress-root-" + rootId ];
|
||||
}
|
||||
|
||||
/**
|
||||
* Round the number to 2 decimals, it's enough for use
|
||||
*/
|
||||
var roundNumber = function( num ) {
|
||||
return Math.round( ( num + Number.EPSILON ) * 100 ) / 100;
|
||||
};
|
||||
|
||||
/**
|
||||
* Get the length/norm of a vector.
|
||||
*
|
||||
* https://en.wikipedia.org/wiki/Norm_(mathematics)
|
||||
*/
|
||||
var vectorLength = function( vec ) {
|
||||
return Math.sqrt( vec.x * vec.x + vec.y * vec.y + vec.z * vec.z );
|
||||
};
|
||||
|
||||
/**
|
||||
* Dot product of two vectors.
|
||||
*
|
||||
* https://en.wikipedia.org/wiki/Dot_product
|
||||
*/
|
||||
var vectorDotProd = function( vec1, vec2 ) {
|
||||
return vec1.x * vec2.x + vec1.y * vec2.y + vec1.z * vec2.z;
|
||||
};
|
||||
|
||||
/**
|
||||
* Cross product of two vectors.
|
||||
*
|
||||
* https://en.wikipedia.org/wiki/Cross_product
|
||||
*/
|
||||
var vectorCrossProd = function( vec1, vec2 ) {
|
||||
return {
|
||||
x: vec1.y * vec2.z - vec1.z * vec2.y,
|
||||
y: vec1.z * vec2.x - vec1.x * vec2.z,
|
||||
z: vec1.x * vec2.y - vec1.y * vec2.x
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* Determine wheter a vector is a zero vector
|
||||
*/
|
||||
var isZeroVector = function( vec ) {
|
||||
return !roundNumber( vec.x ) && !roundNumber( vec.y ) && !roundNumber( vec.z );
|
||||
};
|
||||
|
||||
/**
|
||||
* Scalar triple product of three vectors.
|
||||
*
|
||||
* It can be used to determine the handness of vectors.
|
||||
*
|
||||
* https://en.wikipedia.org/wiki/Triple_product#Scalar_triple_product
|
||||
*/
|
||||
var tripleProduct = function( vec1, vec2, vec3 ) {
|
||||
return vectorDotProd( vectorCrossProd( vec1, vec2 ), vec3 );
|
||||
};
|
||||
|
||||
/**
|
||||
* The world/absolute unit coordinates.
|
||||
*
|
||||
* This coordinate is used by browser to position objects.
|
||||
* It will not be affected by object rotations.
|
||||
* All relative positions will finally be converted to this
|
||||
* coordinate to be used.
|
||||
*/
|
||||
var worldUnitCoordinate = {
|
||||
x: { x:1, y:0, z:0 },
|
||||
y: { x:0, y:1, z:0 },
|
||||
z: { x:0, y:0, z:1 }
|
||||
};
|
||||
|
||||
/**
|
||||
* Make quaternion from rotation axis and angle.
|
||||
*
|
||||
* q = [ cos(½θ), sin(½θ) axis ]
|
||||
*
|
||||
* If the angle is zero, returns the corresponded quaternion
|
||||
* of axis.
|
||||
*
|
||||
* If the angle is not zero, returns the rotating quaternion
|
||||
* which corresponds to rotation about the axis, by the angle θ.
|
||||
*
|
||||
* https://en.wikipedia.org/wiki/Quaternion
|
||||
* https://en.wikipedia.org/wiki/Quaternions_and_spatial_rotation
|
||||
*/
|
||||
var makeQuaternion = function( axis, theta = 0 ) {
|
||||
var r = 0;
|
||||
var t = 1;
|
||||
|
||||
if ( theta ) {
|
||||
var radians = theta * Math.PI / 180;
|
||||
r = Math.cos( radians / 2 );
|
||||
t = Math.sin( radians / 2 ) / vectorLength( axis );
|
||||
}
|
||||
|
||||
var q = [ r, axis.x * t, axis.y * t, axis.z * t ];
|
||||
|
||||
return q;
|
||||
};
|
||||
|
||||
/**
|
||||
* Extract vector from quaternion
|
||||
*/
|
||||
var quaternionToVector = function( quaternion ) {
|
||||
return {
|
||||
x: roundNumber( quaternion[ 1 ] ),
|
||||
y: roundNumber( quaternion[ 2 ] ),
|
||||
z: roundNumber( quaternion[ 3 ] )
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns the conjugate quaternion of a quaternion
|
||||
*
|
||||
* https://en.wikipedia.org/wiki/Quaternion#Conjugation,_the_norm,_and_reciprocal
|
||||
*/
|
||||
var conjugateQuaternion = function( quaternion ) {
|
||||
return [ quaternion[ 0 ], -quaternion[ 1 ], -quaternion[ 2 ], -quaternion[ 3 ] ];
|
||||
};
|
||||
|
||||
/**
|
||||
* Left multiple two quaternion.
|
||||
*
|
||||
* Is's used to combine two rotating quaternion into one.
|
||||
*/
|
||||
var leftMulQuaternion = function( q1, q2 ) {
|
||||
return [
|
||||
( q1[ 0 ] * q2[ 0 ] - q1[ 1 ] * q2[ 1 ] - q1[ 2 ] * q2[ 2 ] - q1[ 3 ] * q2[ 3 ] ),
|
||||
( q1[ 1 ] * q2[ 0 ] + q1[ 0 ] * q2[ 1 ] - q1[ 3 ] * q2[ 2 ] + q1[ 2 ] * q2[ 3 ] ),
|
||||
( q1[ 2 ] * q2[ 0 ] + q1[ 3 ] * q2[ 1 ] + q1[ 0 ] * q2[ 2 ] - q1[ 1 ] * q2[ 3 ] ),
|
||||
( q1[ 3 ] * q2[ 0 ] - q1[ 2 ] * q2[ 1 ] + q1[ 1 ] * q2[ 2 ] + q1[ 0 ] * q2[ 3 ] )
|
||||
];
|
||||
};
|
||||
|
||||
/**
|
||||
* Convert a rotation into a quaternion
|
||||
*/
|
||||
var rotationToQuaternion = function( baseCoordinate, rotation ) {
|
||||
var order = rotation.order ? rotation.order : "xyz";
|
||||
var axes = order.split( "" );
|
||||
var result = [ 1, 0, 0, 0 ];
|
||||
|
||||
for ( var i = 0; i < axes.length; i++ ) {
|
||||
var deg = rotation[ axes[ i ] ];
|
||||
if ( !deg || ( Math.abs( deg ) < 0.0001 ) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// All CSS rotation is based on the rotated coordinate
|
||||
// So we need to calculate the rotated coordinate first
|
||||
var coordinate = baseCoordinate;
|
||||
if ( i > 0 ) {
|
||||
coordinate = {
|
||||
x: rotateByQuaternion( baseCoordinate.x, result ),
|
||||
y: rotateByQuaternion( baseCoordinate.y, result ),
|
||||
z: rotateByQuaternion( baseCoordinate.z, result )
|
||||
};
|
||||
}
|
||||
|
||||
result = leftMulQuaternion(
|
||||
makeQuaternion( coordinate[ axes[ i ] ], deg ),
|
||||
result );
|
||||
|
||||
}
|
||||
|
||||
return result;
|
||||
};
|
||||
|
||||
/**
|
||||
* Rotate a vector by a quaternion.
|
||||
*/
|
||||
var rotateByQuaternion = function( vec, quaternion ) {
|
||||
var q = makeQuaternion( vec );
|
||||
|
||||
q = leftMulQuaternion(
|
||||
leftMulQuaternion( quaternion, q ),
|
||||
conjugateQuaternion( quaternion ) );
|
||||
|
||||
return quaternionToVector( q );
|
||||
};
|
||||
|
||||
/**
|
||||
* Rotate a vector by rotaion sequence.
|
||||
*/
|
||||
var rotateVector = function( baseCoordinate, vec, rotation ) {
|
||||
var quaternion = rotationToQuaternion( baseCoordinate, rotation );
|
||||
|
||||
return rotateByQuaternion( vec, quaternion );
|
||||
};
|
||||
|
||||
/**
|
||||
* Given a rotation, return the rotationed coordinate
|
||||
*/
|
||||
var rotateCoordinate = function( coordinate, rotation ) {
|
||||
var quaternion = rotationToQuaternion( coordinate, rotation );
|
||||
|
||||
return {
|
||||
x: rotateByQuaternion( coordinate.x, quaternion ),
|
||||
y: rotateByQuaternion( coordinate.y, quaternion ),
|
||||
z: rotateByQuaternion( coordinate.z, quaternion )
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* Return the angle between two vector.
|
||||
*
|
||||
* The axis is used to determine the rotation direction.
|
||||
*/
|
||||
var angleBetweenTwoVector = function( axis, vec1, vec2 ) {
|
||||
var vecLen1 = vectorLength( vec1 );
|
||||
var vecLen2 = vectorLength( vec2 );
|
||||
|
||||
if ( !vecLen1 || !vecLen2 ) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
var cos = vectorDotProd( vec1, vec2 ) / vecLen1 / vecLen2 ;
|
||||
var angle = Math.acos( cos ) * 180 / Math.PI;
|
||||
|
||||
if ( tripleProduct( vec1, vec2, axis ) > 0 ) {
|
||||
return angle;
|
||||
} else {
|
||||
return -angle;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Return the angle between a vector and a plane.
|
||||
*
|
||||
* The plane is determined by an axis and a vector on the plane.
|
||||
*/
|
||||
var angleBetweenPlaneAndVector = function( axis, planeVec, rotatedVec ) {
|
||||
var norm = vectorCrossProd( axis, planeVec );
|
||||
|
||||
if ( isZeroVector( norm ) ) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 90 - angleBetweenTwoVector( axis, rotatedVec, norm );
|
||||
};
|
||||
|
||||
/**
|
||||
* Calculated a order specified rotation sequence to
|
||||
* transform from the world coordinate to required coordinate.
|
||||
*/
|
||||
var coordinateToOrderedRotation = function( coordinate, order ) {
|
||||
var axis0 = order[ 0 ];
|
||||
var axis1 = order[ 1 ];
|
||||
var axis2 = order[ 2 ];
|
||||
var reversedOrder = order.split( "" ).reverse().join( "" );
|
||||
|
||||
var rotate2 = angleBetweenPlaneAndVector(
|
||||
coordinate[ axis2 ],
|
||||
worldUnitCoordinate[ axis0 ],
|
||||
coordinate[ axis0 ] );
|
||||
|
||||
// The r2 is the reverse of rotate for axis2
|
||||
// The coordinate1 is the coordinate before rotate of axis2
|
||||
var r2 = { order: reversedOrder };
|
||||
r2[ axis2 ] = -rotate2;
|
||||
|
||||
var coordinate1 = rotateCoordinate( coordinate, r2 );
|
||||
|
||||
// Calculate the rotation for axis1
|
||||
var rotate1 = angleBetweenTwoVector(
|
||||
coordinate1[ axis1 ],
|
||||
worldUnitCoordinate[ axis0 ],
|
||||
coordinate1[ axis0 ] );
|
||||
|
||||
// Calculate the rotation for axis0
|
||||
var rotate0 = angleBetweenTwoVector(
|
||||
worldUnitCoordinate[ axis0 ],
|
||||
worldUnitCoordinate[ axis1 ],
|
||||
coordinate1[ axis1 ] );
|
||||
|
||||
var rotation = { };
|
||||
rotation.order = order;
|
||||
rotation[ axis0 ] = roundNumber( rotate0 );
|
||||
rotation[ axis1 ] = roundNumber( rotate1 );
|
||||
rotation[ axis2 ] = roundNumber( rotate2 );
|
||||
|
||||
return rotation;
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns the possible rotations from unit coordinate
|
||||
* to specified coordinate.
|
||||
*/
|
||||
var possibleRotations = function( coordinate ) {
|
||||
var orders = [ "xyz", "xzy", "yxz", "yzx", "zxy", "zyx" ];
|
||||
var rotations = [ ];
|
||||
|
||||
for ( var i = 0; i < orders.length; ++i ) {
|
||||
rotations.push(
|
||||
coordinateToOrderedRotation( coordinate, orders[ i ] )
|
||||
);
|
||||
}
|
||||
|
||||
return rotations;
|
||||
};
|
||||
|
||||
/**
|
||||
* Calculate a degree which in range (-180, 180] of baseDeg
|
||||
*/
|
||||
var nearestAngle = function( baseDeg, deg ) {
|
||||
while ( deg > baseDeg + 180 ) {
|
||||
deg -= 360;
|
||||
}
|
||||
|
||||
while ( deg < baseDeg - 180 ) {
|
||||
deg += 360;
|
||||
}
|
||||
|
||||
return deg;
|
||||
};
|
||||
|
||||
/**
|
||||
* Given a base rotation and multiple rotations, return the best one.
|
||||
*
|
||||
* The best one is the one has least rotate from base.
|
||||
*/
|
||||
var bestRotation = function( baseRotate, rotations ) {
|
||||
var bestScore;
|
||||
var bestRotation;
|
||||
|
||||
for ( var i = 0; i < rotations.length; ++i ) {
|
||||
var rotation = {
|
||||
order: rotations[ i ].order,
|
||||
x: nearestAngle( baseRotate.x, rotations[ i ].x ),
|
||||
y: nearestAngle( baseRotate.y, rotations[ i ].y ),
|
||||
z: nearestAngle( baseRotate.z, rotations[ i ].z )
|
||||
};
|
||||
|
||||
var score = Math.abs( rotation.x - baseRotate.x ) +
|
||||
Math.abs( rotation.y - baseRotate.y ) +
|
||||
Math.abs( rotation.z - baseRotate.z );
|
||||
|
||||
if ( !i || ( score < bestScore ) ) {
|
||||
bestScore = score;
|
||||
bestRotation = rotation;
|
||||
}
|
||||
}
|
||||
|
||||
return bestRotation;
|
||||
};
|
||||
|
||||
/**
|
||||
* Given a coordinate, return the best rotation to achieve it.
|
||||
*
|
||||
* The baseRotate is used to select the near rotation from it.
|
||||
*/
|
||||
var coordinateToRotation = function( baseRotate, coordinate ) {
|
||||
var rotations = possibleRotations( coordinate );
|
||||
|
||||
return bestRotation( baseRotate, rotations );
|
||||
};
|
||||
|
||||
/**
|
||||
* Apply a relative rotation to the base rotation.
|
||||
*
|
||||
* Calculate the coordinate after the rotation on each axis,
|
||||
* and finally find out a one step rotation has the effect
|
||||
* of two rotation.
|
||||
*
|
||||
* If there're multiple way to accomplish, select the one
|
||||
* that is nearest to the base.
|
||||
*
|
||||
* Return one rotation has the same effect.
|
||||
*/
|
||||
var combineRotations = function( rotations ) {
|
||||
|
||||
// No rotation
|
||||
if ( rotations.length <= 0 ) {
|
||||
return { x:0, y:0, z:0, order:"xyz" };
|
||||
}
|
||||
|
||||
// Find out the base coordinate
|
||||
var coordinate = worldUnitCoordinate;
|
||||
|
||||
// One by one apply rotations in order
|
||||
for ( var i = 0; i < rotations.length; i++ ) {
|
||||
coordinate = rotateCoordinate( coordinate, rotations[ i ] );
|
||||
}
|
||||
|
||||
// Calculate one rotation from unit coordinate to rotated
|
||||
// coordinate. Because there're multiple possibles,
|
||||
// select the one nearest to the base
|
||||
var rotate = coordinateToRotation( rotations[ 0 ], coordinate );
|
||||
|
||||
return rotate;
|
||||
};
|
||||
|
||||
var translateRelative = function( relative, prevRotation ) {
|
||||
var result = rotateVector(
|
||||
worldUnitCoordinate, relative, prevRotation );
|
||||
result.rotate = combineRotations(
|
||||
[ prevRotation, relative.rotate ] );
|
||||
|
||||
return result;
|
||||
};
|
||||
|
||||
var lib = {
|
||||
translateRelative: translateRelative
|
||||
};
|
||||
|
||||
roots[ "impress-root-" + rootId ] = lib;
|
||||
return lib;
|
||||
};
|
||||
|
||||
// Let impress core know about the existence of this library
|
||||
window.impress.addLibraryFactory( { rotation: libraryFactory } );
|
||||
|
||||
} )( document, window );
|
||||
|
||||
/**
|
||||
* Autoplay plugin - Automatically advance slideshow after N seconds
|
||||
*
|
||||
@@ -3671,9 +4101,9 @@
|
||||
( function( document, window ) {
|
||||
"use strict";
|
||||
|
||||
var api;
|
||||
var startingState = {};
|
||||
|
||||
var api;
|
||||
var toNumber;
|
||||
var toNumberAdvanced;
|
||||
|
||||
@@ -3683,12 +4113,21 @@
|
||||
if ( !prev ) {
|
||||
|
||||
// For the first step, inherit these defaults
|
||||
prev = { x:0, y:0, z:0, relative: { x:0, y:0, z:0 } };
|
||||
prev = {
|
||||
x:0, y:0, z:0,
|
||||
rotate: { x:0, y:0, z:0, order:"xyz" },
|
||||
relative: {
|
||||
position: "absolute",
|
||||
x:0, y:0, z:0,
|
||||
rotate: { x:0, y:0, z:0, order:"xyz" }
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
var ref = prev;
|
||||
if ( data.relTo ) {
|
||||
|
||||
var ref = document.getElementById( data.relTo );
|
||||
ref = document.getElementById( data.relTo );
|
||||
if ( ref ) {
|
||||
|
||||
// Test, if it is a previous step that already has some assigned position data
|
||||
@@ -3696,7 +4135,42 @@
|
||||
prev.x = toNumber( ref.getAttribute( "data-x" ) );
|
||||
prev.y = toNumber( ref.getAttribute( "data-y" ) );
|
||||
prev.z = toNumber( ref.getAttribute( "data-z" ) );
|
||||
prev.relative = {};
|
||||
|
||||
var prevPosition = ref.getAttribute( "data-rel-position" ) || "absolute";
|
||||
|
||||
if ( prevPosition !== "relative" ) {
|
||||
|
||||
// For compatibility with the old behavior, doesn't inherit otherthings,
|
||||
// just like a reset.
|
||||
prev.rotate = { x:0, y:0, z:0, order: "xyz" };
|
||||
prev.relative = {
|
||||
position: "absolute",
|
||||
x:0, y:0, z:0,
|
||||
rotate: { x:0, y:0, z:0, order:"xyz" }
|
||||
};
|
||||
} else {
|
||||
|
||||
// For data-rel-position="relative", inherit all
|
||||
prev.rotate.y = toNumber( ref.getAttribute( "data-rotate-y" ) );
|
||||
prev.rotate.x = toNumber( ref.getAttribute( "data-rotate-x" ) );
|
||||
prev.rotate.z = toNumber(
|
||||
ref.getAttribute( "data-rotate-z" ) ||
|
||||
ref.getAttribute( "data-rotate" ) );
|
||||
|
||||
// We also inherit relatives from relTo slide
|
||||
prev.relative = {
|
||||
position: prevPosition,
|
||||
x: toNumberAdvanced( ref.getAttribute( "data-rel-x" ), 0 ),
|
||||
y: toNumberAdvanced( ref.getAttribute( "data-rel-y" ), 0 ),
|
||||
z: toNumberAdvanced( ref.getAttribute( "data-rel-z" ), 0 ),
|
||||
rotate: {
|
||||
x: toNumberAdvanced( ref.getAttribute( "data-rel-rotate-x" ), 0 ),
|
||||
y: toNumberAdvanced( ref.getAttribute( "data-rel-rotate-y" ), 0 ),
|
||||
z: toNumberAdvanced( ref.getAttribute( "data-rel-rotate-z" ), 0 ),
|
||||
order: ( ref.getAttribute( "data-rel-rotate-order" ) || "xyz" )
|
||||
}
|
||||
};
|
||||
}
|
||||
} else {
|
||||
window.console.error(
|
||||
"impress.js rel plugin: Step \"" + data.relTo + "\" is not defined " +
|
||||
@@ -3717,34 +4191,95 @@
|
||||
}
|
||||
}
|
||||
|
||||
// While ``data-rel-reset="relative"`` or just ``data-rel-reset``,
|
||||
// ``data-rel-x/y/z`` and ``data-rel-rotate-x/y/z`` will have default value of 0,
|
||||
// instead of inherit from previous slide.
|
||||
//
|
||||
// If ``data-rel-reset="all"``, ``data-rotate-*`` are not inherited from previous slide too.
|
||||
// So ``data-rel-reset="all" data-rotate-x="90"`` means
|
||||
// ``data-rotate-x="90" data-rotate-y="0" data-rotate-z="0"``, we doesn't need to
|
||||
// bother clearing all unneeded attributes.
|
||||
|
||||
var inheritRotation = true;
|
||||
if ( el.hasAttribute( "data-rel-reset" ) ) {
|
||||
|
||||
// Don't inherit from prev, just use the relative setting for current element
|
||||
prev.relative = {
|
||||
position: prev.relative.position,
|
||||
x:0, y:0, z:0,
|
||||
rotate: { x:0, y:0, z:0, order: "xyz" } };
|
||||
|
||||
if ( data.relReset === "all" ) {
|
||||
inheritRotation = false;
|
||||
}
|
||||
}
|
||||
|
||||
var step = {
|
||||
x: toNumber( data.x, prev.x ),
|
||||
y: toNumber( data.y, prev.y ),
|
||||
z: toNumber( data.z, prev.z ),
|
||||
rotate: {
|
||||
x: toNumber( data.rotateX, 0 ),
|
||||
y: toNumber( data.rotateY, 0 ),
|
||||
z: toNumber( data.rotateZ || data.rotate, 0 ),
|
||||
order: data.rotateOrder || "xyz"
|
||||
},
|
||||
relative: {
|
||||
position: data.relPosition || prev.relative.position,
|
||||
x: toNumberAdvanced( data.relX, prev.relative.x ),
|
||||
y: toNumberAdvanced( data.relY, prev.relative.y ),
|
||||
z: toNumberAdvanced( data.relZ, prev.relative.z )
|
||||
z: toNumberAdvanced( data.relZ, prev.relative.z ),
|
||||
rotate: {
|
||||
x: toNumber( data.relRotateX, prev.relative.rotate.x ),
|
||||
y: toNumber( data.relRotateY, prev.relative.rotate.y ),
|
||||
z: toNumber( data.relRotateZ, prev.relative.rotate.z ),
|
||||
order: data.rotateOrder || "xyz"
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// The final relatives maybe or maybe not the same with orignal data-rel-*
|
||||
var relative = step.relative;
|
||||
|
||||
if ( step.relative.position === "relative" && inheritRotation ) {
|
||||
|
||||
// Calculate relatives based on previous slide
|
||||
relative = api.lib.rotation.translateRelative(
|
||||
step.relative, prev.rotate );
|
||||
|
||||
// Convert rotations to values that works with step.rotate
|
||||
relative.rotate.x -= step.rotate.x;
|
||||
relative.rotate.y -= step.rotate.y;
|
||||
relative.rotate.z -= step.rotate.z;
|
||||
}
|
||||
|
||||
// Relative position is ignored/zero if absolute is given.
|
||||
// Note that this also has the effect of resetting any inherited relative values.
|
||||
if ( data.x !== undefined ) {
|
||||
step.relative.x = 0;
|
||||
relative.x = step.relative.x = 0;
|
||||
}
|
||||
if ( data.y !== undefined ) {
|
||||
step.relative.y = 0;
|
||||
relative.y = step.relative.y = 0;
|
||||
}
|
||||
if ( data.z !== undefined ) {
|
||||
step.relative.z = 0;
|
||||
relative.z = step.relative.z = 0;
|
||||
}
|
||||
if ( data.rotateX !== undefined || !inheritRotation ) {
|
||||
relative.rotate.x = step.relative.rotate.x = 0;
|
||||
}
|
||||
if ( data.rotateY !== undefined || !inheritRotation ) {
|
||||
relative.rotate.y = step.relative.rotate.y = 0;
|
||||
}
|
||||
if ( data.rotateZ !== undefined || data.rotate !== undefined || !inheritRotation ) {
|
||||
relative.rotate.z = step.relative.rotate.z = 0;
|
||||
}
|
||||
|
||||
// Apply relative position to absolute position, if non-zero
|
||||
// Note that at this point, the relative values contain a number value of pixels.
|
||||
step.x = step.x + step.relative.x;
|
||||
step.y = step.y + step.relative.y;
|
||||
step.z = step.z + step.relative.z;
|
||||
step.x = step.x + relative.x;
|
||||
step.y = step.y + relative.y;
|
||||
step.z = step.z + relative.z;
|
||||
step.rotate.x = step.rotate.x + relative.rotate.x;
|
||||
step.rotate.y = step.rotate.y + relative.rotate.y;
|
||||
step.rotate.z = step.rotate.z + relative.rotate.z;
|
||||
|
||||
return step;
|
||||
};
|
||||
@@ -3766,7 +4301,16 @@
|
||||
z: el.getAttribute( "data-z" ),
|
||||
relX: el.getAttribute( "data-rel-x" ),
|
||||
relY: el.getAttribute( "data-rel-y" ),
|
||||
relZ: el.getAttribute( "data-rel-z" )
|
||||
relZ: el.getAttribute( "data-rel-z" ),
|
||||
rotateX: el.getAttribute( "data-rotate-x" ),
|
||||
rotateY: el.getAttribute( "data-rotate-y" ),
|
||||
rotateZ: el.getAttribute( "data-rotate-z" ),
|
||||
rotate: el.getAttribute( "data-rotate" ),
|
||||
relRotateX: el.getAttribute( "data-rel-rotate-x" ),
|
||||
relRotateY: el.getAttribute( "data-rel-rotate-y" ),
|
||||
relRotateZ: el.getAttribute( "data-rel-rotate-z" ),
|
||||
relPosition: el.getAttribute( "data-rel-position" ),
|
||||
rotateOrder: el.getAttribute( "data-rotate-order" )
|
||||
} );
|
||||
var step = computeRelativePositions( el, prev );
|
||||
|
||||
@@ -3774,6 +4318,17 @@
|
||||
el.setAttribute( "data-x", step.x );
|
||||
el.setAttribute( "data-y", step.y );
|
||||
el.setAttribute( "data-z", step.z );
|
||||
el.setAttribute( "data-rotate-x", step.rotate.x );
|
||||
el.setAttribute( "data-rotate-y", step.rotate.y );
|
||||
el.setAttribute( "data-rotate-z", step.rotate.z );
|
||||
el.setAttribute( "data-rotate-order", step.rotate.order );
|
||||
el.setAttribute( "data-rel-position", step.relative.position );
|
||||
el.setAttribute( "data-rel-x", step.relative.x );
|
||||
el.setAttribute( "data-rel-y", step.relative.y );
|
||||
el.setAttribute( "data-rel-z", step.relative.z );
|
||||
el.setAttribute( "data-rel-rotate-x", step.relative.rotate.x );
|
||||
el.setAttribute( "data-rel-rotate-y", step.relative.rotate.y );
|
||||
el.setAttribute( "data-rel-rotate-z", step.relative.rotate.z );
|
||||
prev = step;
|
||||
}
|
||||
};
|
||||
@@ -3787,28 +4342,27 @@
|
||||
event.detail.api.lib.gc.pushCallback( function() {
|
||||
var steps = startingState[ root.id ];
|
||||
var step;
|
||||
var attrs = [
|
||||
[ "x", "relX" ],
|
||||
[ "y", "relY" ],
|
||||
[ "z", "relZ" ],
|
||||
[ "rotate-x", "relRotateX" ],
|
||||
[ "rotate-y", "relRotateY" ],
|
||||
[ "rotate-z", "relRotateZ" ],
|
||||
[ "rotate-order", "relRotateOrder" ]
|
||||
];
|
||||
|
||||
while ( step = steps.pop() ) {
|
||||
|
||||
// Reset x/y/z in cases where this plugin has changed it.
|
||||
if ( step.relX !== null ) {
|
||||
if ( step.x === null ) {
|
||||
step.el.removeAttribute( "data-x" );
|
||||
} else {
|
||||
step.el.setAttribute( "data-x", step.x );
|
||||
}
|
||||
}
|
||||
if ( step.relY !== null ) {
|
||||
if ( step.y === null ) {
|
||||
step.el.removeAttribute( "data-y" );
|
||||
} else {
|
||||
step.el.setAttribute( "data-y", step.y );
|
||||
}
|
||||
}
|
||||
if ( step.relZ !== null ) {
|
||||
if ( step.z === null ) {
|
||||
step.el.removeAttribute( "data-z" );
|
||||
} else {
|
||||
step.el.setAttribute( "data-z", step.z );
|
||||
for ( var i = 0; i < attrs.length; i++ ) {
|
||||
if ( step[ attrs[ i ][ 1 ] ] !== null ) {
|
||||
if ( step[ attrs[ i ][ 0 ] ] === null ) {
|
||||
step.el.removeAttribute( "data-" + attrs[ i ][ 0 ] );
|
||||
} else {
|
||||
step.el.setAttribute(
|
||||
"data-" + attrs[ i ][ 0 ], step[ attrs[ i ][ 0 ] ] );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user