Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Angular ng-swipe with youtube iframe

I'm trying to build simply slider with images and youtube videos. I want make it works fine on touch devices, so I want to use ng-swipe-* from angular's ngTouch module. Unfortunately swipe doesn't work over youtube's iframe. I tried to set lower z-index: -10;, but then I cannot play the video.

Do you have any idea how to solve this problem?

There is a snippet:

var app = angular.module('app', ['ngTouch']);

app.controller('ctrl', function($scope) {
  $scope.msg = function(msg) {
    alert(msg);
  }
});
.ok {
  width: 300px;
  height: 100px;
  background: green;
}
<script src="https://code.angularjs.org/1.4.8/angular.min.js"></script>
<script src="https://code.angularjs.org/1.4.8/angular-touch.min.js"></script>
<div ng-app="app">
  <div ng-controller="ctrl" ng-swipe-right="msg('right')" ng-swipe-left="msg('left')">
    <div class="ok">swipe works here</div>
    <div>
      <iframe width="300" height="200" src="https://www.youtube.com/embed/dQw4w9WgXcQ" frameborder="0" allowfullscreen></iframe>
    </div>
  </div>
</div>

(the best way to test it, is to run it in Chrome developer console and emulate on touch device)

like image 532
akn Avatar asked Jan 12 '16 19:01

akn


2 Answers

Here's a pretty hacky workaround: using two overlay divs, set to the right and the left of the player allows the user to play and pause, and setting the height to 80% allows them to use the menu on the bottom. This is not perfect, but it kind of works!

Note 1: It's kind of buggy if you play it here, so I'm adding a codepen: http://codepen.io/anon/pen/LGjwYZ

Second version, a little bit more bloated but with more area coverage: http://codepen.io/anon/pen/rxzXxB

Note 2: I used a transparent background on the divs for demonstrational purposes.

var app = angular.module('app', ['ngTouch']);

app.controller('ctrl', function($scope) {
  $scope.msg = function(msg) {
    alert(msg);
  }
});
.ok {
  width: 300px;
  height: 100px;
  background: green;
}
<script src="https://code.angularjs.org/1.4.8/angular.min.js"></script>
<script src="https://code.angularjs.org/1.4.8/angular-touch.min.js"></script>
<div ng-app="app">
  <div ng-controller="ctrl" ng-swipe-right="msg('right')" ng-swipe-left="msg('left')">
    <div class="ok">swipe works here</div>
    <div style="position:relative; height:200px; width:300px;">
        <iframe style="position:absolute;width:100%;height:100%;z-index:10;" src="https://www.youtube.com/embed/dQw4w9WgXcQ"></iframe>
        <div style="background:rgba(0,0,0,0.3);height:80%;width:40%;left:0;position:absolute;z-index:20;"></div>
      <div style="background:rgba(0,0,0,0.3);height:80%;width:40%;right:0;position:absolute;z-index:20;"></div>
</div>
  </div>
</div>
like image 114
fnune Avatar answered Oct 15 '22 21:10

fnune


The issue is that you don't have control of events within the iframe, so can't tell when the user swipes over that area. The work around I suggest is to replace the iframe with a image placeholder while not watching. In order to do this use YouTube's Iframe API to keep track of video events. When the video goes from play to pause we will hide the video and show the image. Here is a demo.

HTML

<div ng-app="app">
  <div ng-controller="ctrl" ng-swipe-right="msg($event, 'right')" ng-swipe-left="msg($event, 'left')">
    <div id="player"></div>
    <img id="player-cover" src="http://img.youtube.com/vi/M7lc1UVf-VE/hqdefault.jpg" />
  </div>
</div>

JS

On initiation it hides the video. When ever the image is clicked it shows and plays the video. When the video goes from paused to play onPlayerStateChange handles toggling the image and video. Every time the swiping event gets called on the image it also triggers the click event handler for the image. The variable swiping keeps track of if the event was just a click or also a swipe.

var app = angular.module('app', ['ngTouch']);

app.controller('ctrl', function($scope) {
  $scope.msg = function(event, msg) {
    swiping = true;
    alert(msg);
  }
});

// keep track of the user swiping. onYouTubeIframeAPIReady needs to occur outside of Angular. 
var swiping = false;

// Youtube related. 
document.getElementById('player').style.display = 'none';
document.getElementById('player-cover').addEventListener("click", function() {
    if (swiping) {
        swiping = false;
        return;
    }
    document.getElementById('player').style.display = 'block';
    player.playVideo();
});

// This code loads the IFrame Player API code asynchronously.
var tag = document.createElement('script');
tag.src = "https://www.youtube.com/iframe_api";
var firstScriptTag = document.getElementsByTagName('script')[0];
firstScriptTag.parentNode.insertBefore(tag, firstScriptTag);

// This function creates an <iframe> (and YouTube player) after the API code downloads.
var player;
function onYouTubeIframeAPIReady() {
    player = new YT.Player('player', {
        height: '390',
        width: '640',
        videoId: 'M7lc1UVf-VE',
        events: { 'onStateChange': onPlayerStateChange }
    });
}

function onPlayerStateChange(event) {
    if (event.data === YT.PlayerState.PAUSED || event.data === YT.PlayerState.ENDED) {
        document.getElementById('player-cover').style.display = 'block';
        document.getElementById('player').style.display = 'none';
    } else {
        document.getElementById('player-cover').style.display = 'none';
        document.getElementById('player').display = 'block';
    }
}
like image 23
jjbskir Avatar answered Oct 15 '22 21:10

jjbskir