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:
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)
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)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With