How to check if a video is done playing - javascript

I want to detect if the method of an object is called.
I have a video player in my page and when it is done playing, I want to show some contents.
For example:
function videoSet(){
var instance = this;
this.video = $('#video')
this.video.bind("ended", function() {
instance.endVideo()
});
}
videoSet.prototype.endVideo = function(){
$('#test1').css('visibility','visible');
}
//more methods...
function main(){
this.init();
}
main.prototype.init = function(){
this.video = new videoSet() //init an video object.
// more code...
//I need to know if the video is ended...
}
var mainObj = new main();
Inside my endVideo method, I have $('#test1').css('visibility','visible'); but I have so much code in my main object and I want to be able to detect if the video has ended in my main object.
Is that possible?

You can have multiple eventListeners on DOM objects...
var Video = function () { this.video = document.querySelector("#my-video"); };
var Main = function () {
var myVideo = new Video();
myVideo.video.addEventListener("ended", function () { console.log("It's over!"); });
myVideo.video.addEventListener("ended", function () {
console.log("Play something else.");
});
};
Main();
There's nothing stopping you from adding an event-listener to the object from inside of main.
Moreover, this leads to custom event systems -- Publisher/Subscriber or Observer or "Emitters".
If you can implement one of these, on an object, then your object can create/fire custom events, and pass custom data, and any time you have access to that object, you can subscribe (as long as you know what the events are called, and how to handle the data you will get back).
For example, you might want to have a video-playing system that loads the next film (or a countdown screen, until the next film, et cetera, for continuous playback, with a playlist that highlights the current film).
var VideoPlayer = function (id) {
var player = this;
player.video = document.getElementById(id);
// attach an emitter-system with "on", "off" and "emit", or whatever you choose
addEmitter(player);
player.load = function (video) { player.video.src = video.src; };
player.init = function () {
player.video.addEventListener("ended", function () {
// fire custom-event
player.emit("video-ended");
});
player.video.addEventListener("canplay", function () {
// auto-play video, fire event
player.video.play();
player.emit("video-playing");
});
};
},
VideoPlaylist = function (id, videos) {
var playlist = this;
playlist.root = document.getElementById(id);
playlist.videos = videos;
playlist.addVideo = function (video) { /* attach each video to the root */ };
playlist.currentVideoIndex = 0;
playlist.currentVideo = playlist.videos[playlist.currentVideoIndex];
playlist.select = function (i) {
playlist.currentVideoIndex = i;
playlist.currentVideo = playlist.videos[i];
// fire a custom event
playlist.emit("load-video", playlist.currentVideo);
};
playlist.nextVideo = function () {
var i = (playlist.currentVideoIndex + 1) % playlist.videos.length; // loops
playlist.select(i);
};
addEmitter(playlist);
};
var Main = function () {
var video_player = new VideoPlayer("my-player"),
video_playlist = new VideoPlaylist("my-playlist", [{ src : "...", title : "A" }, { src : "...", title : "B" }]);
video_player.on("video-ended", video_playlist.next);
video_playlist.on("load-video", video_player.load );
// add another listener for another component, to handle on-screen controls
video_player.on("video-playing", video_controller.show_playing);
// add another listener for another component, to display the data about the video
video_playlist.on("load-video", video_description.display);
// add another listener for another component to load comments
video_playlist.on("load-video", video_comments.load);
};
Main();
This isn't a particularly Java-like way of writing programs, but JavaScript isn't particularly Java-like (though you can make it look similar).
You'll notice that inside of the Main function all I'm doing is wiring behaviours together, rather than writing out custom logic.
Of course, you can take this way further...
...and I haven't shown you how my emitter is made, but they're not hard to make, either.
Publisher/Subscriber or Observer or Emitter implementations are great practice for JS (and very easy in JS compared to other languages).
But as you can see, with a little thinking, this is a really simple and versatile way of dispatching code.

You can use an ended flag in the videoSet object like
function videoSet() {
var instance = this;
this.ended=false;
this.video = $('#video')
this.video.bind("ended", function () {
instance.endVideo()
});
}
videoSet.prototype.endVideo = function () {
$('#test1').css('visibility', 'visible');
this.ended=true;
}
videoSet.prototype.isEnded = function () {
return this.ended;
}
//more methods...
function main() {
this.init();
//later
if(myVideoSet.isEnded()){
console.log('completed')
}
}

Related

paper.Tool is not working on Multiple canvas

I have two canvas the first one is working good, but when I initialize the second one the paper.Tool does not work properly, sometimes the event onMouseMove works others not.
var dataLoad;
var mypapers = []
$(document).ready(function () {
dataLoad = new DataLoad();
mypapers[0] = new paper.PaperScope();
mypapers[1] = new paper.PaperScope();
mypapers[0].setup(document.getElementById('dataCanvas'));
dataLoad.Init();
});
// "returnedData" THIS ARRAY COMES FROM AN AJAX CALL
DataLoad.prototype = {
Init: function () {
var self = this;
var paperData = new
DataReader(document.getElementById('dataCanvas'));
paperData.Init(returnedData[i],mypapers[0]);
paperData.Draw(true);
self.datas.push(paperData);
}
});
Till here everything is good the first canvas is populated with the graphics I setted.
DataReader.prototype = {
Init: function (data,mypaper) {
var self = this;
paper = mypaper;
self.paper = paper;
self.toolPan = new self.paper.Tool()
self.toolPan.activate();
self.toolPan.onMouseDrag = function (event) {
var delta = event.downPoint.subtract(event.point)
self.paper.view.scrollBy(delta)
};
self.toolPan.onMouseMove = function (event) {
self.OnMouseMove(event);
};
self.toolPan.onMouseUp = function (event) {
// AFTER MAKE A SELECTION OF ITEMS IN THE CANVAS CALLING THE SECOND CANVAS
var core = self.HighlightElementsInBox();
self.dc = new DefineComponent();
self.dc.Init(core);
$('#DCCanvas').modal('toggle'); // THE CANVAS IS INSIDE THIS BOOTSTRAP MODAL
}
}
});
/* this initialize the second canvas that basically creates another instance of the same prototype i use to manipulate paperjs in the first canvas */
DefineComponent.prototype = {
Init: function (dataCore) {
var self = this;
mypapers[1].setup(document.getElementById('DCCanvas')); // setting second canvas
var paperDataDC = new DataReader(document.getElementById('DCCanvas'));
paperDataDC.Init(dataCore,mypapers[1]);
paperDataDC.Draw(true);
self.datas.push(paperDatasDC);
}
});
In this second canvas all is drawn correctly, but the events onmousedrag and onmousemove does not works properly the first one move the canvas in another position where the mouse is not and mousemove works only in some places of the canvas not in all.
As you are creating two different paperScopes you will need to toggle between them when working with one or the other.
You are saving both paperScopes inside "mypapers" array
mypapers[0] = new paper.PaperScope();
mypapers[1] = new paper.PaperScope();
So to use any of those you should do
mypapers[0].activate();
// or
mypapers[1].activate();
Check out this (min setup) example of what I mean above.
Also, follow stefan's suggestion if you want more help on this since it's hard for people to try to help without a minimal working example

Javascript object function call wont work

I'm working on a HTML5 soundboard, but i've hit a bit of a snag...
I'm trying to get a stop function to work on all of the sounds at once that are played. Unfortunatly when i call this function from a buttonpress, the object doesn't appear to have a stop function. The code for the actual sound element is the following:
// Container to keep all sounds in one place. This is a Dictionary within a dictionary to be able to search by catagory.
var sounds = {};
// Counter to keep track of unique ID's
var lastID = 0;
// Base class for initializing Any class
var Base = function(methods){
var base = function() {
this.initialize.apply(this, arguments);
};
for (var property in methods) {
base.prototype[property] = methods[property];
}
if (!base.prototype.initialize) base.prototype.initialize = function(){};
return base;
};
//Complete class for the Sound object. Generates its own DIV's and HTML5 tags to play stuff.
var Sound = Base({
// Init all the variables.
initialize: function(name, file, target='Sounds') {
this.name = name;
this.file = file
this.button = null;
this.audioelement;
this.id = lastID + 1;
this.target = target;
lastID ++;
// Check if the catagory is there, if not: create it with a placeholder object
var catagory = sounds[this.target];
if(catagory == null){
sounds[this.target] = {99:null};
}
sounds[this.target][this.id] = this;
// Call init function
this.init();
},
play : function() {
obj = this
if(obj.audioelement.paused == true){
obj.audioelement.play();
}else{
obj.audioelement.pause();
obj.audioelement.fastSeek(0);
}
},
stop : function(){
obj = this;
obj.audioelement.pause();
},
init : function(){
// Statement for JS class based shenanigans.
obj = this
// Create a button and add some text to it
obj.button = document.createElement("BUTTON");
obj.button.appendChild(document.createTextNode(obj.name));
// Set ID's and names to keep track of this button
obj.button.id = obj.id;
obj.button.name = obj.target;
// Get or create parent element. Used for catagory based display
var el = getOrCreateElement(obj.target)
el.appendChild(obj.button);
// Create audio element and set appropriate settings
obj.audioelement = document.createElement("AUDIO");
obj.audioelement.src = obj.file;
obj.audioelement.name
obj.button.appendChild(obj.audioelement);
// Add function to play/pause to button
obj.button.onclick = buttonClicked;
});
function buttonClicked(){
// Fetch sound from dicionary container using the name and id from the button [SET AT SOUND.INIT()]
var sound = sounds[this.name][this.id];
// Call the play function in [SOUND]
sound.play();
}
And for the stopall function:
function stopAll(){
// Scroll through the entire dictionary
for ( var key in sounds){
for ( var id in sounds[key]){
// Check if the sound is not a placeholder
if(id == 99){
continue;
}
// Call stop function with fetched object.
var sound = sounds[key][id];
sound.stop();
}
}
}
The weird thing is is that the play function does seem to work, but not the stop function. It says that the object doesn't have that specific function...
Any ideas would be appriciated!
WM
for ( var x in object) loops over a few more properties than just methods, including ones on the base object's prototype.
If you console.log(id); within that inner loop you will see the extra ones.
Try adding this inside your inner for loop:
if (typeof id !== 'function') {
continue;
}
Edit: this isn't quite correct but I'm not in a position to see what it should be right now. It's almost there, from memory! Keep playing with it.

Is it possible for different classes to detect 'emits' from eachother in Nodejs?

I am struggling with what seems to be a simple concept which makes me think what I am doing can't be done.
In nodejs, if class objectA.emits('hey there'), can class objectB.on('hey there') repsond with 'yo'?
Object A and B have nothing to do with eachother other than they both extend EventEmitter and are in the same nodejs app.
Sorry if this question has been asked before, I can't find it.
Yes
That's pretty much it.
When dealing with Observer/Publisher-Subscriber patterns (or Mediator Patterns), the point is that it really doesn't matter what type of class it is that's doing the "emitting".
Assuming that A is an emitter:
var B = { doStuff : function () { console.log("Yo!"); } };
A.addListener("someEvent", B.doStuff);
A.emit("someEvent");
If you actually want them to talk back and forth, then you need to manually subscribe them to one another...
Assuming that both A AND B are emitters:
B.doStuff = function () { this.emit("B's event", "Yo!"); };
A.doThing = function (param) { console.log(param); };
B.addListener("B's event", A.doThing);
A.addListener("A's event", B.doStuff.bind(B));
A.emit("A's event");
Alternatively, you should look into a Mediator pattern (which also "emits", but is intended to be 1 object which mediates between many objects who don't know one another, but use the same event-names and pass well-defined data-structures, like a good API should).
Assuming that Mediator is an emitter, and A, B and C aren't:
var A = {
getData : function (request) { /* network call */ this.dataCallback(data); },
dataCallback : function (data) { Mediator.emit("data-recieved", data); }
},
B = {
display : document.getElementById("data-display"),
showData : function (data) { /* make DOM representation */ }
},
C = {
input : document.getElementById("request-input"),
button : document.getElementById("request-button"),
getRequest : function () {
var request = this.input.value;
this.requestData(request);
this.disableButton();
},
requestData : function (request) { Mediator.emit("data-request", request); },
disableButton : function () { this.button.disabled = true; },
enableButton : function () { this.button.disabled = false; }
};
Mediator.addListener("data-request", A.getData.bind(A));
Mediator.addListener("data-received", B.showData.bind(B));
Mediator.addListener("data-received", C.enableButton.bind(C));
C.button.addEventListener("click", C.getRequest.bind(C), false);
So now you've got 3 classes who know nothing about one another, each has its own special purpose, and the only expectations that they have of "one another" are that event-names and data-types are appropriate.
They all know about Mediator.
If you want Mediator to be further abstracted, then you can pass a reference to it when you're making your class:
function A (param1, param2) {
var emitter = null;
this.setEmitter = function (myEmitter) { emitter = myEmitter; };
this.emit = function (evt, data) {
if (!emitter) { return; }
emitter.emit(evt, data);
};
this.subscribe = function (evt, callback) {
if (!emitter) { return; }
emitter.addListener(evt, callback);
};
/* rest of the object */
};
var a = new A();
var b = new A();
a.setEmitter(Mediator);
a.subscribe("some-evt", a.doSomething.bind(a));
b.setEmitter(Mediator);
b.subscribe("other-evt", b.doSomethingElse.bind(b));
a.emit("other-evt", { /* data */ });
a and b don't have to be the same class, here, at all.
And now they DO work in the way that you're imagining.
Both have used Dependency Injection ("Inversion of Control") to point to the same emitter (Moderator), so they're both working off of the same event-list, without even knowing it, and using their own methods to subscribe to Moderators events.

Dynamic event building in JavaScript

I'd like to create an event for each function in a script, then inject the event trigger into the end of the function.
This way I can see exactly when each function has completed and use the events like hooks for other functions
If I can do it dynamically, I can add as many new functions as I like without having to create and append these events.
Here's a basic example of what I'm trying to do, this won't actually work, but it gives you an idea. I have been using jQuery, but I'll accept any JavaScript framework at all, and any method.
var obj = {};
(function()
{
this.init = function()
{
// loop through every function
$.each(this, function(k, v)
{
// create an event for every function
$('body').bind(v, function()
{
console.log('Event: ' + v + ' Finished');
});
// Add a event trigger into each specific function in the loop
this[v].call($('body').trigger(v));
});
}
this.another_function = function()
{
// do something
}
this.some_function = function()
{
/do something
}
}).apply(obj);
obj.init();
(edit) The script itself basically renders a Calendar, but there are a lot of callbacks, ajax requests, buttons. etc... If I could tie each feature down to an event, it would make my life easier when extending it, adding new features etc...
Loop through every function, replace it with new one, which calls original function on the same object and triggers event on body.
var obj = { };
(function()
{
this.init = function()
{
var self = this;
foreach(var name in this) {
if (typeof k !== 'Function') continue;
if (name ==='init') continue;
var original = this[name];
var newFunc = function() {
original.apply(self, arguments);
$('body').trigger(name);
}
this[name] = newFunc;
}
}
this.another_function = function()
{
// do something
}
this.some_function = function()
{
/do something
}
}).apply(obj);
obj.init();

What is a good approach to be able setting function to object in JavaScript?

//namespace
if (!window.SlidePanel) {
window.SlidePanel = (function () {
var SlidePanel = {};
return SlidePanel;
})();
}
SlidePanel.panel = function (el) {
this.$ = el;
}
SlidePanel.panel.prototype = {
insert: function () {
},
show: function () {
},
hide: function () {
}
}
SlidePanel.up = new SlidePanel.panel($('div#up-panel'));
SlidePanel.bottom = new SlidePanel.panel($('div#bottom-panel'));
SlidePanel.left = new SlidePanel.panel($('div#left-panel'));
SlidePanel.right = new SlidePanel.panel($('div#right-panel'));
I want to be able to set show and hide functions in some place of code. I thought to add setShowFn and setHideFn function to SlidePanel.panel.prototype like this
SlidePanel.panel.prototype = {
...
setShowFn: function (fn) {
this.show = fn;
},
setHideFn: function (fn) {
this.hide = fn;
}
}
Is this a good approach or there is more elegant way to do this?
If you want to override the show or hide function on just one instance of a SlidePanel.panel, you're free to just update that instance:
SlidePanel.up.show = function() { /* ... */ };
That breaks the inheritance of show for that specific instance, without changing any other instances that still use the show property from the prototype.
If you want to update show for all instances that are using the inherited version, you can do this at any time:
SlidePanel.panel.prototype.show = function() { /* ... */ };
...since the instances have a reference back to the prototype, and so changes to the prototype happen "live." Note that any instance on which you've done the first example above will be unaffected, because it's not using the version of show from the prototype anymore.
And yes, you're free to encapsulate this in your setShowFn and setHideFn functions if you want to; just be aware that there's nothing other than convention/documentation preventing code from assigning to the properties directly even if you do.

Categories