Skip to content

Commit

Permalink
Add relative move and rotate to rel plugin (impress#794)
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
thawk authored Apr 24, 2022
1 parent d3760df commit 629f768
Show file tree
Hide file tree
Showing 18 changed files with 10,559 additions and 123 deletions.
4 changes: 2 additions & 2 deletions build.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ var Terser = require("terser");

var files = ['src/impress.js'];
// Libraries from src/lib
files.push('src/lib/gc.js', 'src/lib/util.js')
files.push('src/lib/gc.js', 'src/lib/util.js', 'src/lib/rotation.js')
// Plugins from src/plugins
files.push('src/plugins/autoplay/autoplay.js',
'src/plugins/blackout/blackout.js',
Expand Down Expand Up @@ -71,4 +71,4 @@ html += '</body>\n</html>'

filename = path.resolve(__dirname, 'examples', 'index.html');
fs.writeFileSync(filename, html);
console.log(filename);
console.log(filename);
169 changes: 169 additions & 0 deletions examples/3D-positions/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,169 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<title>relative rotations</title>
<link href="..\..\css\impress-common.css" rel="stylesheet" />
<style type="text/css" media="screen">
#overview {
background: none;
border: none;
box-shadow: none;
width: 1800px;
height: 1300px;
}

#overview div {
width: 100%;
height: 100%;
}

.step {
position: relative;
width: 1000px;
height: 1000px;
padding: 40px 60px;
margin: 20px auto;

box-sizing: border-box;

line-height: 1.5;

background-color: yellow;
border-radius: 10px;
box-shadow: 0 2px 6px rgba(0, 0, 0, .1);

text-shadow: 0 2px 2px rgba(0, 0, 0, .1);

font-family: 'Open Sans', Arial, sans-serif;
font-size: 40pt;
letter-spacing: -1px;
border: solid 2px red;

opacity: 40%;
}

.step.active {
opacity: 100%;
}

.step.ring2 {
background-color: cyan;
}

.step.box {
background-color: purple;
opacity: 70%;
}

.step.box1 {
background-color: lightblue;
}
</style>
</head>

<body class="impress-not-supported">
<div id="impress" data-width="2000" data-height="1500">
<div id="overview" class="step overview" data-rel-position="relative" data-x="-1000" data-y="-1500" data-z="100" data-scale="3" data-rotate-x="45" data-rotate-y="10">
<div>
<h2>Demo of <code>data-rel-position</code></h2>
<p>This demo use <code>data-rel-position="relative"</code><br>
and <code>data-rel-rotate-x/y/z</code><br>
to easy 3D positioning of slides.</p>
</div>
</div>

<div id="box-front" class="step box" data-x="-3000" data-y="0" data-z="0" data-rotate-x="0" data-rotate-y="0" data-rotate-z="0">Front
<p>There's two nested box here.</p>
</div>
<div id="box-front1" class="step box1" data-rel-reset data-rel-z="-200" data-scale="0.6">Inside Front</div>
<div id="box-right1" class="step box1" data-rel-reset data-rel-x="300" data-rel-z="-300" data-rel-rotate-y="90" data-scale="0.6">Inside Right</div>
<div id="box-right" class="step box" data-rel-reset data-rel-z="200">Right</div>
<div id="box-back" class="step box" data-rel-reset data-rel-x="500" data-rel-z="-500" data-rel-rotate-y="90">Back</div>
<div id="box-back1" class="step box1" data-rel-reset data-rel-z="-200" data-scale="0.6">Inside Back</div>
<div id="box-top1" class="step box1" data-rel-reset data-rel-y="-300" data-rel-z="-300" data-rel-rotate-x="90" data-scale="0.6">Inside Top</div>
<div id="box-top" class="step box" data-rel-reset data-rel-z="200">Top</div>
<div id="box-left" class="step box" data-rel-reset data-rel-x="500" data-rel-z="-500" data-rel-rotate-y="90">Left</div>
<div id="box-left1" class="step box1" data-rel-reset data-rel-z="-200" data-scale="0.6">Inside Left</div>
<div id="box-bottom1" class="step box1" data-rel-reset data-rel-x="300" data-rel-z="-300" data-rel-rotate-y="90" data-scale="0.6">Inside Bottom</div>
<div id="box-bottom" class="step box" data-rel-reset data-rel-z="200">Bottom</div>

<div id="ring1-1" class="step" data-rel-reset="all" data-x="0" data-y="0" data-z="0" data-rotate-y="10">
<p>Slide one</p>
<p>This is a ring of 8 slides.</p>
<p>It's easy constucted with data-rel-position="relative" without calculates the coordinates of all slides.</p>
</div>

<div id="ring1-2" class="step" data-rel-rotate-y="45" data-rel-z="-354" data-rel-x="854">
<p>Slide two</p>
<p>The position of this slide is calculated as relatived position and rotation of the first slide.</p>
<p>The following slides don't need to set any position attributes, they are inherit from this slide.</p>
</div>

<div id="ring1-3" class="step">
<p>Slide three</p>
</div>

<div id="ring1-4" class="step">
<p>Slide four</p>
</div>

<div id="ring1-5" class="step">
<p>Slide five</p>
</div>

<div id="ring1-6" class="step">
<p>Slide six</p>
</div>

<div id="ring1-7" class="step">
<p>Slide seven</p>
</div>

<div id="ring1-8" class="step">
<p>Slide eight</p>
</div>

<div id="ring2-1" class="step ring2" data-rel-reset="all" data-x="-500" data-y="0" data-z="-1514" data-rotate-x="90" data-rotate-y="270" data-rotate-z="0">
<p>Slide one</p>
<p>This is another ring of slides.</p>
<p>Except for the this slide, its code is just cloned from the yellow ring.</p>
<p>Just change the position of first slide, all the following slides are position relatived to it.</p>
</div>

<div id="ring2-2" class="step ring2" data-rel-rotate-y="45" data-rel-z="-354" data-rel-x="854" data-rel-y="0">
<p>Slide two</p>
</div>

<div id="ring2-3" class="step ring2">
<p>Slide three</p>
</div>

<div id="ring2-4" class="step ring2">
<p>Slide four</p>
</div>

<div id="ring2-5" class="step ring2">
<p>Slide five</p>
</div>

<div id="ring2-6" class="step ring2">
<p>Slide six</p>
</div>

<div id="ring2-7" class="step ring2">
<p>Slide seven</p>
</div>

<div id="ring2-8" class="step ring2">
<p>Slide eight</p>
</div>
</div>

<div id="impress-toolbar"></div>
<div id="impress-help"></div>

<script type="text/javascript" src="../../js/impress.js"></script>
<script>impress().init();</script>
</body>
<html>
34 changes: 24 additions & 10 deletions examples/classic-slides/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -188,7 +188,7 @@ <h1>Bullet points</h1>
Notation shouldn't be a surprise. We use `data-rotate="30"` attribute, meaning that this
element should be rotated by 30 degrees clockwise.
-->
<div class="step slide" data-rel-x="2200" data-rel-y="600" data-rotate="30">
<div class="step slide" data-rel-position="relative" data-rel-x="2200" data-rel-y="600" data-rel-rotate-z="30">
<h1>A blockquote &amp; image</h1>
<img src="images/3476636111_c551295ca4_b.jpg"
alt="Mother Teresa holding a newborn baby"
Expand All @@ -200,10 +200,14 @@ <h1>A blockquote &amp; image</h1>
</blockquote>

<div class="notes">
We use <code>data-rel-position="relative"</code> to make <code>data-rel-rotate-*</code> work,
and make <code>data-rel-x/data-rel-y/data-rel-y</code> be calculated at the coordination related to previous slide.
The relative position and rotation will be inherited by following slides,
so it's not necessary to repeat it again and again.
</div>
</div>

<div class="step slide" data-rel-x="1600" data-rel-y="1600" data-rotate="60">
<div class="step slide">
<h1>More text styles</h1>
<p>As usual, use <em>em</em> to emphasize, <br />
<strong>strong</strong> for strong, <u>u</u> for underline,<br />
Expand All @@ -216,7 +220,7 @@ <h1>More text styles</h1>
</div>
</div>

<div class="step slide" data-rel-x="600" data-rel-y="2200" data-rotate="90">
<div id="motions" class="step slide">
<h1>Motion effects 101</h1>
<p>Items on the slide can</p>
<p class="fly-in fly-out">Fly in</p>
Expand Down Expand Up @@ -246,22 +250,32 @@ <h1>Motion effects 101</h1>
</div>
</div>

<div id="addons" class="step slide title" data-rel-x="-600" data-rel-y="2200" data-rotate="120">
<div id="zoom" class="step" data-rel-reset data-rel-x="-0.25w" data-rel-y="0.5h" data-scale="0.5">
<div class="notes">
<p>This step zoom in to left bottom of previous slide to see to small text.</p>
<p>It's a empty and transparent.</p>
<p><code>data-rel-reset</code> is used to prevent this step from inheriting the relative positioning from previous slide.</p>
</div>
</div>

<div id="addons" class="step slide title" data-rel-to="motions">
<h2>Add-ons</h2>
<div class="notes">
<p>This version of impress.js includes several add-ons, striving to make this a
full featured presentation app.</p>
<p>The previous step breaks the slide flow, changes the relative position and rotation.</p>
<p>This slide use <code>data-rel-to</code> to inherit relative position and rotation from the slide before previous slide.</p>
</div>
</div>

<div class="step slide" data-rel-x="-1600" data-rel-y="1600" data-rotate="150" data-autoplay="3">
<div class="step slide" data-autoplay="3">
<h1>Impress.js plugins</h1>
<ul>
<li>A new <a href="https://github.com/impress/impress.js/blob/master/src/plugins/README.md">plugin framework</a> allows for rich extensibility,
without bloating the core rendering library.
<ul>
<li class="substep">Press 'P' to open a presenter console.</li>
<li class="substep">When you move the mouse, navigation controls are visible on your bottom left</li>
<li class="substep">When you move the mouse, navigation controls are visible on your bottom right</li>
<li class="substep">Autoplay makes the slides advance after a timeout</li>
<li class="substep">Relative positioning plugin is often a more convenient way to position your slides when editing. (<a href="https://github.com/impress/impress.js/blob/master/examples/classic-slides/index.html">See html for this presentation.</a>)</li>
</ul>
Expand All @@ -277,7 +291,7 @@ <h1>Impress.js plugins</h1>
</div>
</div>

<div class="step slide" data-rel-x="-2200" data-rel-y="600" data-rotate="180">
<div class="step slide">
<h1>Highlight.js</h1>
<pre><code>
// `init` API function that initializes (and runs) the presentation.
Expand All @@ -303,7 +317,7 @@ <h1>Highlight.js</h1>
</div>
</div>

<div class="step slide" data-rel-x="-2200" data-rel-y="-600" data-rotate="210">
<div class="step slide">
<h1>Mermaid.js</h1>
<div class="mermaid">
%% This is a comment in mermaid markup
Expand All @@ -330,7 +344,7 @@ <h1><a href="http://docs.mathjax.org/en/latest/start.html">MathJax.js</a></h1>
</div>
</div>

<div id="markdown" class="step slide markdown" data-rel-x="-1600" data-rel-y="-1600" data-rotate="240">
<div id="markdown" class="step slide markdown">
# Markdown.js

* [Markdown.js](https://github.com/evilstreak/markdown-js) integration: for authors in a hurry!
Expand All @@ -344,7 +358,7 @@ <h1><a href="http://docs.mathjax.org/en/latest/start.html">MathJax.js</a></h1>
* [A more advanced Markdown presentation is here.](../markdown/)
</div>

<div id="acme" class="step slide" data-rel-x="-600" data-rel-y="-2200" data-rotate="270">
<div id="acme" class="step slide">
<ul>
<li>Remember, in <em>impress.js</em> the full power of HTML5, CSS3 &amp; JavaScript is always at your fingertips!</li>
<li>For example, you can use tables, forms, or dynamic charts as you would on any web page:</li>
Expand Down
1 change: 1 addition & 0 deletions examples/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
<body><h1>Example presentations</h1>
<ul><br />
<li><a href="2D-navigation/">2D-navigation</a></li>
<li><a href="3D-positions/">3D-positions</a></li>
<li><a href="3D-rotations/">3D-rotations</a></li>
<li><a href="classic-slides/">classic-slides</a></li>
<li><a href="cube/">cube</a></li>
Expand Down
Loading

0 comments on commit 629f768

Please sign in to comment.