Skip to content

Instantly share code, notes, and snippets.

@CodeMyUI
Created January 6, 2020 00:08
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save CodeMyUI/7aa2e733bd68eb0b14d18679bfb449f4 to your computer and use it in GitHub Desktop.
Save CodeMyUI/7aa2e733bd68eb0b14d18679bfb449f4 to your computer and use it in GitHub Desktop.
SVG Morphing Play Button
<div class="overflow">
<div id="play-button-container">
<svg id="button-circle-svg" viewBox="0 0 100 100">
<style type="text/css">
.st0 {
fill: #DDDDDD;
stroke:#010101;
stroke-width: 0px;
}
}
</style>
<circle id="button-circle"
class="st0" cx="50" cy="50" r="50"/>
</svg>
<svg id="play-triangle-svg" viewBox="0 0 100 100">
<style>
#play-triangle {
fill: black;
}
#triangle-tween-target {
display: none;
}
</style>
<polygon id="play-triangle" points="37,74.1 76.8,51.1 37,28.2 "/>
<rect id="triangle-tween-target" x="47.6" y="46.7" width="16" height="9"/>
</svg>
<iframe id="youtube-video" width="560" height="315" src="https://www.youtube.com/embed/Mh4f9AYRCZY?enablejsapi=1" frameborder="0" gesture="media" allow="encrypted-media" allowfullscreen></iframe>
<div class="video-text">
Watch Video
</div>
</div>
</div>
var $triangleTweenTarget = $('#triangle-tween-target');
var $playTriangle = $('#play-triangle');
MorphSVGPlugin.convertToPath($triangleTweenTarget);
MorphSVGPlugin.convertToPath($playTriangle);
var clicked = false;
// In the next line, .progress(1).pause(0) is a tip from @greensock to force processing of morphs immediately
var morph = TweenMax.to('#play-triangle', 0.5,
{ morphSVG: $triangleTweenTarget,
scale: 5,
transformOrigin: "center center"
}).progress(1).pause(0);
var $pbContainer = $('#play-button-container');
var $buttonCircleSvg = $('#button-circle-svg');
var $buttonCircle = $('#button-circle');
var $playTriangleSvg = $('#play-triangle-svg');
$pbContainer.on('click', function(){
if(!clicked){
clicked =true;
TweenMax.to($buttonCircleSvg, 0.2, {scale: getScale(), opacity: 0.8});
TweenMax.to($buttonCircle, 0.5, {fill: '#333333'});
morph.play();
TweenMax.to($playTriangleSvg, 0.5,
{ width: $(window).width(),
height: $(window).height(),
x: -1 * $pbContainer.offset().left,
y: -1 * $pbContainer.offset().top,
onStart: playVideo,
onComplete: moveVideo
});
} else {
clicked = false;
TweenMax.to($buttonCircleSvg, 0.5, {scale: 1});
morph.reverse();
TweenMax.to($buttonCircle, 0.5, {fill: '#DDDDDD'});
TweenMax.to($playTriangleSvg, 0.5,
{ width: $pbContainer.width(),
height: $pbContainer.height(),
x: 0,
y: 0,
scale: 1,
onStart: stopVideo
});
}
//get the minimum scale for the play button to cover the screen
function getScale() {
let buttonPosition =
{ x: $playTriangleSvg.offset().left + ($playTriangleSvg.width()/2),
y: $playTriangleSvg.offset().top + ($playTriangleSvg.height()/2)
};
let $window = $(window);
let farthestCorner =
{ x: (buttonPosition.x > $window.width() / 2) ? 0 : $window.width(),
y: (buttonPosition.y > $window.height() / 2) ? 0 : $window.height()
};
let a = Math.abs(buttonPosition.x - farthestCorner.x);
let b = Math.abs(buttonPosition.y - farthestCorner.y);
let hypotenuse = Math.sqrt(a*a + b*b);
return hypotenuse / ($playTriangleSvg.width() / 2);
}
function playVideo() {
player.playVideo();
}
var $youtubeVideo = $('#youtube-video');
var $playTriangle = $('#play-triangle');
function moveVideo() {
let pbcOffset = $pbContainer.offset();
let boundingBox = $playTriangle[0].getBoundingClientRect();
TweenMax.set($youtubeVideo,
{ x: boundingBox.left - pbcOffset.left,
y: boundingBox.top - pbcOffset.top,
width: boundingBox.width,
height: boundingBox.height});
showVideo();
}
function showVideo() {
TweenMax.to($youtubeVideo, 0.3, {opacity: 1});
$youtubeVideo.addClass('-visible');
}
function stopVideo() {
player.stopVideo();
$youtubeVideo.removeClass('-visible');
TweenMax.to($youtubeVideo, 0, {opacity: 0});
}
});
var player;
function onYouTubeIframeAPIReady() {
player = new YT.Player('youtube-video');
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/1.20.3/TweenMax.min.js"></script>
<script src="https://s3-us-west-2.amazonaws.com/s.cdpn.io/16327/MorphSVGPlugin.min.js"></script>
<script src="https://www.youtube.com/iframe_api"></script>
.overflow
width: 100vw
height: 100vh
overflow: hidden
#play-button-container
position: relative
top: 100px
left: 200px
width: 100px
height: 100px
&:hover
cursor: pointer
#button-circle-svg,
#play-triangle-svg
position: absolute
top: 0
left: 0
#youtube-video
position: absolute
top: 0
left: 0
opacity: 0
pointer-events: none
&.-visible
pointer-events: auto
.video-text
padding-top: 110px
text-align: center
font-family: Arial

SVG Morphing Play Button

I wanted to create a smooth play button experience that naturally leads the user's eye from the area of focus (the play button) to the next place they'll want to be looking (the playing video). This allows the user's visual cortex (our brain's GPU) to handle the task transition which allows the rest of the cortex (our brain's CPU) to stay immersed in the website or content (h/t @rachelnabors).

I used two SVGs, a circle for the button which, after expanding, also serves as the overlay. The second SVG has two shapes, the play button triangle, and the 16:9 rectangle that it will morph into. Morphing was done using Greensock's MorphSVG plugin. Centering the video is done by setting the dimensions of the triangle SVG to match the window dimensions.

Post a comment if you have any questions!

Also thanks to @greensock for helping me solve a subtle bug with this that was preventing the video from centering.

A Pen by Eric Johnson on CodePen.

License.

@Yacine-22
Copy link

It doesn't work

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment