Other is ok, but the setting of currentTime:
I tried some ways like:
videojs("example_video_1", {}, function() {
this.currentTime(200);
this.play();
});
And this is not working.
videojs("example_video_1").ready(function(){
this.currentTime(200);
});
This also doesn't work.
var dom = document.getElementById('example_video_1');
dom.addEventListener("loadedmetadata", function() {
dom.currentTime = 100;
}, false); // ok for no video.js
videojs(dom);
Not working. Even reverse the line of addEventListener and init videojs.
And I tried the videojs event.
var player = videojs("example_video_1");
alert(player.addEvent);
alert(player.addEventListener);
these API all not exists, so how do I bind Event in videojs?
This is how I got the video playback on a defined position at startup (it removes the problem that the video first started and only afterwards jumped to a video position):
$(document).ready(function()
{
var timecode = 120;
var initdone = false;
// wait for video metadata to load, then set time
video.on("loadedmetadata", function(){
video.currentTime(timecode);
});
// iPhone/iPad need to play first, then set the time
// events: https://www.w3.org/TR/html5/embedded-content-0.html#mediaevents
video.on("canplaythrough", function(){
if(!initdone)
{
video.currentTime(timecode);
initdone = true;
}
});
}); // END ready
Oh, by lucky, i found an example in https://github.com/videojs/video.js
var dom = document.getElementById('example_video_1');
videojs(dom, {}, function(){
this.on('loadedmetadata', function(){
this.currentTime(500);
});
});
this is work, the API to bind event is player.on('event', fn);
videojs is cool~
Related
I'm rending map using this angular library for mapbox ngx-mapbox-gl
I'm showing a popup on mouseenter event.
mapInstance.on("mouseenter", "scoots_layers", function (e) {
var _lat = e.lngLat.lat;
var _lng = e.lngLat.lng;
var coordinates = [_lng, _lat];
this.popup = new Popup({
closeButton: true,
closeOnClick: true,
});
this.popup.setLngLat(coordinates)
.setHTML('<button (click)="goToPage()">Hello </button>')
.addTo(mapInstance);
});
Popup is working fine. But the click event of button is not triggered.
Maybe if you do it this way it works
this.popup.setLngLat(coordinates)
.setHTML('<button id="myBtn">Hello </button>')
.addTo(mapInstance);
});
and in your ts file
document.getElementById("myBtn").addEventListener("click", function(){
alert('say something...');
});
The MovieClip class in the EaselJS module has a loop property which can be set to true or false, causing the movie clip to play infinitely or only once. http://www.createjs.com/docs/easeljs/classes/MovieClip.html
I need to play a movie clip (banner ad) three times. How can that be done?
This is the init function:
<script>
var canvas, stage, exportRoot;
function init() {
// --- write your JS code here ---
canvas = document.getElementById("canvas");
images = images||{};
var loader = new createjs.LoadQueue(false);
loader.addEventListener("fileload", handleFileLoad);
loader.addEventListener("complete", handleComplete);
loader.loadManifest(lib.properties.manifest);
}
function handleFileLoad(evt) {
if (evt.item.type == "image") { images[evt.item.id] = evt.result; }
}
function handleComplete(evt) {
exportRoot = new lib.banner_728x90();
stage = new createjs.Stage(canvas);
stage.addChild(exportRoot);
stage.update();
stage.enableMouseOver();
createjs.Ticker.setFPS(lib.properties.fps);
createjs.Ticker.addEventListener("tick", stage);
}
</script>
There is currently no loop count support, nor any events from MovieClip indicating when an animation finishes. The latter isn't a bad idea, feel free to log a bug in GitHub.
One solution you could use would be to dispatch some custom events from a timeline script in Animate:
this.dispatchEvent("walkend");
Then you can listen for the event, and handle it yourself.
var loopCount = 0;
exportRoot.myClip.on("walkend", function(event) {
loopCount++;
if (loopCount > 2) {
doSomething();
event.remove(); // No longer get this event.
}
});
Hope that helps.
I have an OpenLayers 3.9.0 map. I also have a pair of LonLat coordinates that I am tracking from an external source and updating onto the map. I am continuously re-centering the map on these coordinates:
function gets_called_when_I_have_updated_coords() {
map.getView.setCenter(coords);
}
What I want is to disable this auto-centering whenever the user interacts with the map. In other words, I want this:
var auto_center = true;
function gets_called_when_I_have_updated_coords() {
if (auto_center) {
map.getView.setCenter(coords);
}
}
function user_started_interacting() {
auto_center = false;
}
// But where should this function be attached to?
// where.on('what?', user_started_interacting);
I don't know how to detect a user interaction.
I expected that the default interactions had some kind of event, so that when the user starts dragging/rotating/zooming the map, an event would be triggered and my code would run. I could not find such event.
Here, the user is dragging:
map.on('pointermove', function(evt){
if(evt.dragging){
//user interacting
console.info('dragging');
}
});
Here, the user is changing resolution:
map.getView().on('change:resolution', function(evt){
console.info(evt);
});
UPDATE
Some options to detect keyboard interaction:
//unofficial && undocumented
map.on('key', function(evt){
console.info(evt);
console.info(evt.originalEvent.keyIdentifier);
});
//DOM listener
map.getTargetElement().addEventListener('keydown', function(evt){
console.info(evt);
console.info(evt.keyIdentifier);
});
A fiddle to test.
An other approach could be to listen to the pointerdown and pointerup events occurring on the map and while the down is in action, disable your auto-center feature.
map.on('pointerdown', function() {
auto_center = false;
}, this);
map.on('pointerup', function() {
auto_center = true;
}, this);
This approach may need more work, but it would be a start. Thoughts ?
As an workaround, I can attach an event to a change in the view:
map.getView().on('change:center', function(ev){…});
But I must take extra steps to distinguish from code-initiated changes from user-initiated ones. The complete code looks somewhat like this:
var auto_center = true;
var ignore_change_events = false;
function gets_called_when_I_have_updated_coords() {
if (auto_center) {
ignore_change_events = true;
map.getView.setCenter(coords);
ignore_change_events = false;
}
}
map.getView().on('change:center', function() {
if (ignore_change_events) {
return;
}
auto_center = false;
});
Note that this approach breaks if any animation is used (and there is no callback or event for when an animation finishes).
Depending on your project, you may want to try either this solution or Jonatas Walker's solution.
Ive made a pause button for a YouTube video. This worked fine however now I need to clone the video. This is due to how the carousel that im using works and also so the video can be displayed in a Lightbox.
Below is a simplified version of my code. Now the pause button only works on the first video. How can I make a button that will pause all cloned videos?
http://jsfiddle.net/36vr2kjv/2/
<p class="trigger">Trigger</p>
<p class="trigger2">Trigger2</p>
<div class="player-wrap">
<div id="player"></div>
</div>
<div id="player2"></div>
var player;
$(function() {
// 2. 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);
// 3. This function creates an <iframe> (and YouTube player)
// after the API code downloads.
onYouTubeIframeAPIReady = function onYouTubeIframeAPIReady() {
player = new YT.Player('player', {
height: '390',
width: '640',
videoId: 'M7lc1UVf-VE',
events: {
'onReady': onPlayerReady,
'onStateChange': onPlayerStateChange
}
});
}
// 4. The API will call this function when the video player is ready.
function onPlayerReady(event) {
event.target.playVideo();
}
// 5. The API calls this function when the player's state changes.
// The function indicates that when playing a video (state=1),
// the player should play for six seconds and then stop.
var done = false;
function onPlayerStateChange(event) {
if (event.data == YT.PlayerState.PLAYING && !done) {
setTimeout(stopVideo, 6000);
done = true;
}
}
function stopVideo() {
player.stopVideo();
}
$('.trigger').click(function(){
//this works
player.pauseVideo()
});
return player;
});
$(function() {
setTimeout(function(){
$('.player-wrap').clone().appendTo('#player2');
}, 2000);
});
$(function() {
$('.trigger2').click(function(){
// this does not work
player.pauseVideo()
});
});
Actually there is concept of deep cloning and shallow cloning. Shallow cloning does not copy events hence you have to use deep cloning. Where ever you are using clone() instead use clone(true).
For example in above code snippet you can use:
$(function() {
setTimeout(function(){
$('.player-wrap').clone(true).appendTo('#player2');
}, 2000);
});
Issue Description:
What's happening in your code is you are cloning and creating two IDs within a single DOM load, which means your javascript will have conflicting IDs to deal with. The other issue being that the youtube API creation function binds to an ID and not a class.
So after you've cloned your iframe, your original function (held in player) is now pointed at two places... hence the confusion.
Solution:
To combat this, we can use a placeholder. Based on the Youtube Player API Reference, Youtube allows for loading videos to a player object.
player.loadVideoById(videoId:String,
startSeconds:Number,
suggestedQuality:String):Void
[See Youtube API#Queueing_Functions]
We can use classes and object references to reach your goal:
player;
placeholder;
playerCount = 1;
$(function() {
// ... Previous code ... //
/**
* Assuming you have more than one video to play,
* the function will change to allow for incrementing the ids
* of each player made. [UNIQUE IDS]
*/
onYouTubeIframeAPIReady = function onYouTubeIframeAPIReady() {
player = new YT.Player('player-'+playerCount, {
height: '390',
width: '640',
videoId: 'M7lc1UVf-VE',
events: {
'onReady': onPlayerReady,
'onStateChange': onPlayerStateChange
}
});
placeholder = new YT.Player('placeholder', {
height: '390',
width: '640',
});
/**
* Now add a generic class so we can find all of these elements,
* and bind the object to a data instance for access later.
*/
$('#player-' + playerCount).addClass('youtube-player').data('YoutubeAPI', player);
playerCount++;
}
The placeholder comes into play now, when you carousel fires it's beforeChange event, you can access the player element from within the current/next/previous slide using the carousel's event handler and running a $(event.target).find('youtube-player') (or something like that, APIs are different, so YMMV) and access the player instance using $(event.target).find('youtube-player').data('YoutubeAPI') (or whatever you named your data variable).
Then you just find the video id from the original object (using the access scheme from above and taking the id from the youtubeAPI object) and load the video into the placeholder using the API call from above.
I've followed MDN's document to create a toggle button addon.
Everything works fine except one problem:
Open a second browser window (cmd+n or ctrl+n) and click on the toggle button there
Click on the toggle button on the original browser window without closing the toggle button on the second window
the toggle button's panel becomes blank with the following error message:
JavaScript error: resource:///modules/WindowsPreviewPerTab.jsm, line 406: NS_ERR
OR_FAILURE: Component returned failure code: 0x80004005 (NS_ERROR_FAILURE) [nsIT
askbarTabPreview.invalidate]
// ./lib/main.js
var { ToggleButton } = require("sdk/ui/button/toggle");
var panels = require("sdk/panel");
var self = require("sdk/self");
var buttonIndex = 0;
var lastKnownButtonIndex = 0;
var button = ToggleButton({
id: "button",
label: "my button",
icon: {
"16": "./icon-16.png"
},
onClick: handleChange,
});
var panel = panels.Panel({
contentURL: self.data.url("menu.html"),
onHide: handleHide
});
function handleChange(state) {
if (state.checked) {
panel.show({
position: button
});
}
}
function handleHide() {
button.state('window', {checked: false});
}
function assignButtonIndex() {
return (buttonIndex++).toString();
}
The complete addon is here: https://goo.gl/9N3jle
To reproduce: Extract the zip file and $ cd testButton; cfx run and follow the above steps.
I really hope someone can help me with this. Thank you in advance!
It's a bug; you're not doing anything wrong. It's a racing condition between the windows' focus events, and the panel's event, that prevent somehow the panel's hidden event to be emitted properly.
You can try to mitigate with a workaround the issue until is properly fixed. I added some explanation in the bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1174425#c2 but in short, you can try to add a setTimeout to delay a bit when the panel is shown, in order to avoid the racing condition with the window's focus. Something like:
const { setTimeout } = require("sdk/timers");
/* ... your code here ... */
function handleChange(state) {
if (state.checked) {
setTimeout(() => panel.show({ position: button }), 100);
}
}
I am currently using a workaround where I dynamically create a new Panel every time the user presses the toolbar button.
It is faster than the 100ms workaround and also handles a scenario where the user outright closes one of the browser windows while the panel is open. (The 100ms workaround fails in this case and a blank panel is still displayed.)
It works like this:
let myPanel = null;
const toolbarButton = ToggleButton({
...,
onChange: function (state) {
if (state.checked) {
createPanel();
}
}
});
function createPanel(){
// Prevent memory leaks
if(myPanel){
myPanel.destroy();
}
// Create a new instance of the panel
myPanel = Panel({
...,
onHide: function(){
// Destroy the panel instead of just hiding it.
myPanel.destroy();
}
});
// Display the panel immediately
myPanel.show();
}