Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Swipe effect for images in Shiny R

Tags:

plot

r

image

shiny

Is it possible to overlay two images using a swipe effect on a shiny app in R. I have been looking for some implementation but have not found a specific solution. Something similar but not exactly what I am looking for is here

Is this option implemented in shiny.

By swipe I am refering to this:

enter image description here

enter image description here

like image 534
GCGM Avatar asked Dec 21 '18 08:12

GCGM


2 Answers

If you are free to use img() instead of the render...() functions you can simply use the following code:

Reproducible version:

Simply clone this repository: https://github.com/Timag/shiny.slider or devtools::install_github("Timag/shiny.slider") and run app.R.

# runApp(".../shiny.slider/R")
library(shiny)

ui <- fluidPage(
  tags$script(src = "jquery-1.6.1.min.js"),
  tags$script(src = "jquery-ui-1.8.13.custom.min.js"),
  tags$script(src = "jquery.beforeafter-1.4.min.js"),
  tags$script("
            $(function() {
                $('#slider').beforeAfter({
                    introDelay: 2000,
                    imagePath: 'img/',
                    introDuration: 500,
                    showFullLinks: false
                })
              });
  "),
  mainPanel(
    tags$div(id = "slider",
               img(src = "img/Polar-Bear-SliderTest1.jpg", width = 800, height = 533),
               img(src = "img/Polar-Bear-SliderTest2.jpg", width = 800, height = 533)
    )
  )
)

server <- function(input, output, session){}

shinyApp(ui, server)

demo

like image 71
Tonio Liebrand Avatar answered Oct 09 '22 23:10

Tonio Liebrand


The examples from @7hibault comment in a shinyApp.

Example 1 (http://codepen.io/dudleystorey/pen/HkwBo):

library(shiny)

## CSS ######################
css <- HTML("
div#comparison { 
  width: 60vw;
            height: 60vw;
            max-width: 600px;
            max-height: 600px;
            overflow: hidden; }
            div#comparison figure { 
            background-image: url(https://s3-us-west-2.amazonaws.com/s.cdpn.io/4273/photoshop-face-before.jpg); 
            background-size: cover;
            position: relative;
            font-size: 0;
            width: 100%; 
            height: 100%;
            margin: 0; 
            }
            div#comparison figure > img { 
            position: relative;
            width: 100%;
            }
            div#comparison figure div { 
            background-image: url(https://s3-us-west-2.amazonaws.com/s.cdpn.io/4273/photoshop-face-after.jpg);
            background-size: cover;
            position: absolute;
            width: 50%; 
            box-shadow: 0 5px 10px -2px rgba(0,0,0,0.3);
            overflow: hidden;
            bottom: 0;
            height: 100%;
            }

            input[type=range]{
            -webkit-appearance:none;
            -moz-appearance:none;
            position: relative;
            top: -2rem; left: -2%;
            background-color: rgba(255,255,255,0.1);
            width: 102%; 
            }
            input[type=range]:focus { 
            outline: none; 
            }
            input[type=range]:active { 
            outline: none;  
            }

            input[type=range]::-moz-range-track { 
            -moz-appearance:none;
            height:15px;
            width: 98%;
            background-color: rgba(255,255,255,0.1); 
            position: relative;
            outline: none;    
            }
            input[type=range]::active { 
            border: none; 
            outline: none;
            }
            input[type=range]::-webkit-slider-thumb {
            -webkit-appearance:none;
            width: 20px; height: 15px;   
            background: #fff;
            border-radius: 0;
            }
            input[type=range]::-moz-range-thumb {
            -moz-appearance: none;
            width: 20px;
            height: 15px;
            background: #fff;
            border-radius: 0;
            }   
            input[type=range]:focus::-webkit-slider-thumb {
            background: rgba(255,255,255,0.5);
            }
            input[type=range]:focus::-moz-range-thumb {
            background: rgba(255,255,255,0.5);
            }
")
######################
## JS #################
js <- HTML('
function moveDivisor() { 
  divisor.style.width = slider.value+"%";
}

$(document).on("shiny:connected", function(event) {
  var divisor = document.getElementById("divisor"),
  slider = document.getElementById("slider");
});
')

######################

ui <- fluidPage(
  tags$head(tags$style(css)),
  tags$head(tags$script(js)),

  HTML('<div id="comparison">
         <figure>
            <div id="divisor"></div>
         </figure>
         <input type="range" min="0" max="100" value="50" id="slider" oninput="moveDivisor()">
       </div>')
)

server <- function(input, output, session) {}

shinyApp(ui, server)

Example 2 (https://codepen.io/bamf/pen/jEpxOX):

library(shiny)

## CSS ######################
css <- HTML("
  @import 'lesshat';

  .ba-slider {
  position: relative;
  overflow: hidden;
  }

  .ba-slider img {
  width: 100%;
  display:block;
  }

  .resize {
  position: absolute;
  top:0;
  left: 0;
  height: 100%;
  width: 50%;
  overflow: hidden;
  }


  .handle { /* Thin line seperator */
  position:absolute; 
  left:50%;
  top:0;
  bottom:0;
  width:4px;
  margin-left:-2px;

  background: rgba(0,0,0,.5);
  cursor: ew-resize;
  }

  .handle:after {  /* Big orange knob  */
  position: absolute;
  top: 50%;
  width: 64px;
  height: 64px;
  margin: -32px 0 0 -32px;

  content:'\21d4';
  color:white;
  font-weight:bold;
  font-size:36px;
  text-align:center;
  line-height:64px;

  background: #ffb800; /* @orange */
  border:1px solid #e6a600; /* darken(@orange, 5%) */
  border-radius: 50%;
  transition:all 0.3s ease;
  box-shadow:
  0 2px 6px rgba(0,0,0,.3), 
  inset 0 2px 0 rgba(255,255,255,.5),
  inset 0 60px 50px -30px #ffd466; /* lighten(@orange, 20%)*/ 
  }

  .draggable:after {
  width: 48px;
  height: 48px;
  margin: -24px 0 0 -24px;
  line-height:48px;
  font-size:30px;
  }
")
######################
## JS #################
js <- HTML("
$(document).on('shiny:connected', function(event) {
  // Call & init
  $(document).ready(function(){
     $('.ba-slider').each(function(){
     var cur = $(this);
     // Adjust the slider
     var width = cur.width()+'px';
     cur.find('.resize img').css('width', width);
     // Bind dragging events
     drags(cur.find('.handle'), cur.find('.resize'), cur);
     });
  });

  // Update sliders on resize. 
  // Because we all do this: i.imgur.com/YkbaV.gif
  $(window).resize(function(){
     $('.ba-slider').each(function(){
     var cur = $(this);
     var width = cur.width()+'px';
     cur.find('.resize img').css('width', width);
     });
  });

  function drags(dragElement, resizeElement, container) {

      // Initialize the dragging event on mousedown.
      dragElement.on('mousedown touchstart', function(e) {
         dragElement.addClass('draggable');
         resizeElement.addClass('resizable');

         // Check if it's a mouse or touch event and pass along the correct value
         var startX = (e.pageX) ? e.pageX : e.originalEvent.touches[0].pageX;

         // Get the initial position
         var dragWidth = dragElement.outerWidth(),
         posX = dragElement.offset().left + dragWidth - startX,
         containerOffset = container.offset().left,
         containerWidth = container.outerWidth();

         // Set limits
         minLeft = containerOffset + 10;
         maxLeft = containerOffset + containerWidth - dragWidth - 10;

         // Calculate the dragging distance on mousemove.
         dragElement.parents().on('mousemove touchmove', function(e) {

           // Check if it's a mouse or touch event and pass along the correct value
           var moveX = (e.pageX) ? e.pageX : e.originalEvent.touches[0].pageX;

           leftValue = moveX + posX - dragWidth;

           // Prevent going off limits
           if ( leftValue < minLeft) {
           leftValue = minLeft;
           } else if (leftValue > maxLeft) {
           leftValue = maxLeft;
           }

           // Translate the handle's left value to masked divs width.
           widthValue = (leftValue + dragWidth/2 - containerOffset)*100/containerWidth+'%';

           // Set the new values for the slider and the handle. 
           // Bind mouseup events to stop dragging.
           $('.draggable').css('left', widthValue).on('mouseup touchend touchcancel', function () {
               $(this).removeClass('draggable');
               resizeElement.removeClass('resizable');
           });
           $('.resizable').css('width', widthValue);
         }).on('mouseup touchend touchcancel', function(){
             dragElement.removeClass('draggable');
             resizeElement.removeClass('resizable');
         });
         e.preventDefault();
     }).on('mouseup touchend touchcancel', function(e){
         dragElement.removeClass('draggable');
         resizeElement.removeClass('resizable');
     });
  }
});
")

######################

ui <- fluidPage(
  tags$head(tags$style(css)),
  tags$head(tags$script(js)),

  HTML('<div class="ba-slider">
         <img src="http://egegorgulu.com/assets/img/beforeafter/after.jpg" alt="">       
         <div class="resize">
            <img src="http://egegorgulu.com/assets/img/beforeafter/before.jpg" alt="">
         </div>
         <span class="handle"></span>
       </div>
       ')
)

server <- function(input, output, session) {}

shinyApp(ui, server)
like image 45
SeGa Avatar answered Oct 09 '22 23:10

SeGa