Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Replace image in reveal.js

Tags:

reveal.js

Suppose I have two very similar images I want to display in succession (say first is a photo and the second one the same photo with some area highlighted). I'd like to avoid a transition animation and just have the second image replace the first image. Is this possible with reveal.js?

Setting data-transition="none" doesn't work very well because the previous slide still retains its animation.

like image 996
numentar Avatar asked May 12 '14 12:05

numentar


4 Answers

Reveal.js does not have any direct method by itself for doing of what is being asked. However, it can be done using a div container and the fragment feature of reveal.js. The container includes the images, which are absolutely positioned within it, and because of that it has to have fix dimensions.

The following piece of html displays the first image and on the next slide the second image on top of the first one.

<section>
<h1>Slide 1</h1>
<div style="position:relative; width:640px; height:480px; margin:0 auto;">
  <img class="fragment" width="640" height="480" src="img1.jpg" style="position:absolute;top:0;left:0;" />
  <img class="fragment" width="640" height="480" src="img2.jpg" style="position:absolute;top:0;left:0;" />
</div>
</section>

While this piece of html displays the first image and on the next slide the first image fades out and the second image fades in instead.

<section>
<h1>Slide 2</h1>
<div style="position:relative; width:640px; height:480px; margin:0 auto;">
  <img class="fragment fade-out" data-fragment-index="0" width="640" height="480" src="img1.jpg" style="position:absolute;top:0;left:0;" />
  <img class="fragment fade-in" data-fragment-index="0" width="640" height="480" src="img2.jpg" style="position:absolute;top:0;left:0;" />
</div>
</section>
like image 186
mib0163 Avatar answered Oct 23 '22 02:10

mib0163


reveal.js 4.0 introduces a new r-stack class that makes it easier to stack elements on top of each other.

<div class="r-stack">
  <img class="fragment" src="https://placekitten.com/450/300" width="450" height="300">
  <img class="fragment" src="https://placekitten.com/300/450" width="300" height="450">
  <img class="fragment" src="https://placekitten.com/400/400" width="400" height="400">
</div>

The above example fades in images on top of each other. If you want to only show one image at a time you'll need to use slightly different fragment settings.

<div class="r-stack">
  <img class="fragment current-visible" src="...">
  <img class="fragment current-visible" src="...">
  <img class="fragment" src="...">
</div>

You can see examples of how this works in the reveal.js docs https://revealjs.com/layout/#stack

like image 45
hakim Avatar answered Oct 23 '22 03:10

hakim


Another possible solution would be to use Javascript. With this code you can not only replace images, but any content.

It is important to apply the classes content-target and content-source. It is also important to use the display: none; style.

The html could look like:

<section>
    <h3>Headline</h3>
    <div class="content-target"></div>
    <div style="display: none;">
        <div class="content-source fragment" data-fragment-index="0">
            <img src="path/to/image.jpg" />
            <p>Some text</p>
        </div>
        <div class="content-source fragment" data-fragment-index="1">
            <ul>
                <li>List item 1</li>
                <li>List item 2</li>
            </ul>
        </div>
        <div class="content-source fragment" data-fragment-index="2">
            <img src="path/to/another/image.jpg" />
        </div>
    </div>
</section>

Now we add a function fadeContent() and call it every time fragmentshown or fragmenthidden is triggered.

function fadeContent($el, back=false) {
    // If we go back, choose previous element, otherwise current element
    $new = (back ? $el.prev() : $el);
    if($new.length == 0) {
        $text = $el.parent().siblings('.content-target');
        $text.fadeOut(200);
    } else {
        $text = $new.parent().siblings('.content-target');
        $text.hide(0, function() {
            $text.html($new.html());
            $text.fadeIn(300);
        });
    }
}

Reveal.addEventListener('fragmentshown', function(event) {
    // Get first fragment which has "content-source" class
    var $el = $($(event.fragments).filter(function() {
        return $(this).hasClass('content-source')
    })[0]);

    // Show content
    if ($el.hasClass('content-source'))
        fadeContent($el);
});

Reveal.addEventListener('fragmenthidden', function(event) {
    // Get first fragment which has "content-source" class
    var $el = $($(event.fragments).filter(function() {
        return $(this).hasClass('content-source')
    })[0]);

    // Hide element
    if ($el.hasClass('content-source'))
        fadeContent($el, back=true);
});

Since we have just extended the fragment functionality, we can still use the data-fragment-index attribute and change the order.

The solution can easily be optimized/customized.

like image 2
sagacity Avatar answered Oct 23 '22 03:10

sagacity


You can specify two transitions, for entering and for leaving, thus the following works but has a glitch (image flicker when appearing) :

<section data-transition="slide none">
  <img src="timeline2.a.svg">
</section>
<section data-transition="none">
  <img src="timeline2.b.svg">
</section>
<section data-transition="none side">
  <img src="timeline2.c.svg">
</section>

Otherwise this may also be a solution, this is a bit different from what you want but is not bad :

<section data-transition="slide fade-out">
  <img src="timeline2.a.svg">
</section>
<section data-transition="fade-in fade-out">
  <img src="timeline2.b.svg">
</section>
<section data-transition="fade-in side">
  <img src="timeline2.c.svg">
</section>
like image 1
FloFu Avatar answered Oct 23 '22 02:10

FloFu