paper.Tool is not working on Multiple canvas - javascript

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

Related

chart.js v2 update chart without global variable

I am using chart.js v2.5.0.
I want to create charts dynamically without using a global variable.
For example, I want to use code similar to this:
https://jsfiddle.net/DUKEiLL/sf57xw6b/
function UpdateChart(ctrl) {
var config = $("#" + ctrl).data("ChartJs");
config.data.datasets.forEach(function (dataset) {
dataset.data = dataset.data.map(function () {
return randomScalingFactor();
});
});
var ctx = document.getElementById(ctrl).getContext("2d");
var TempMyDoughnut = new Chart(ctx, config);
TempMyDoughnut.update();
}
But it doesn't work properly: when the user presses "update" button and hovers over the chart, previous instance are suddenly displayed.
Since you are creating a new chart on each execution of UpdateChart function, hence you would have to destroy any previous instance of chart to prevent the hover issue.
To accomplish so, you could simply replace your UpdateChart function with the following ...
function UpdateChart(ctrl) {
var config = $("#" + ctrl).data("ChartJs");
config.data.datasets.forEach(function(dataset) {
dataset.data = dataset.data.map(function() {
return randomScalingFactor();
});
});
// destroy previous instance of chart
var meta = config.data.datasets[0]._meta;
for (let i in meta) {
if (meta[i].controller) meta[i].controller.chart.destroy();
}
var ctx = document.getElementById(ctrl).getContext("2d");
var TempMyDoughnut = new Chart(ctx, config);
}
Here is the working example on jsFiddle

D3 dispatch pass in arguments and calling context

I understand that in D3, dispatch can be used to fire events to multiple visualisations according to this example.
I also understand that if I want to call a dispatch from an object and pass in the context, I can use apply as shown here.
However, I'm having a hard time combining the arguments from a D3 dispatch and the context that I want.
// create my dispatcher
var probeDispatch = d3.dispatch("probeLoad");
var line_count = 0;
// load a file with a bunch of JSON and send one entry every 50 ms
var lines = [[0,1],[1,2],[2,0]];
var parse_timer = window.setInterval(
function () {
parse_dispatch();
}, 50
);
function parse_dispatch(){
// send two arguments with my dispatch
probeDispatch.probeLoad(lines[line_count][0], lines[line_count][1]);
line_count += 1;
if(line_count >= lines.length){
//line_count = 0
window.clearInterval(parse_timer);
}
}
// my chart object
var genChart = function(label){
this.label = label;
// assume I've drawn my chart somewhere here
probeDispatch.on(("probeLoad."+this.label), this.probeParse);
// this next line isn't working, since the
// console.log in probeLoad still returns undefined
probeDispatch.probeLoad.apply(this);
};
genChart.prototype = {
probeParse: function(probeData, simTime) {
// How do I get the context from the object that's calling probeParse
// into the probeParse scope?
var self = this;
console.log(self.label);
}
};
new genChart("pants");
new genChart("shirt");
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>
It does set the context properly when you see "pants" in the console.
But then there are 3 undefined's logged, because you also call
// send two arguments with my dispatch
probeDispatch.probeLoad(lines[line_count][0], lines[line_count][1]);
without supplying context.
You need
probeDispatch.probeLoad.apply(instanceOfGenChart, [lines[line_count][0], lines[line_count][1]]);
But enabling that also requires moveing parse_dispatch down the page.
// create my dispatcher
var probeDispatch = d3.dispatch("probeLoad");
var line_count = 0;
// load a file with a bunch of JSON and send one entry every 50 ms
var lines = [[0,1],[1,2],[2,0]];
var parse_timer = window.setInterval(
function () {
parse_dispatch();
}, 50
);
// my chart object
var genChart = function(label){
this.label = label;
// assume I've drawn my chart somewhere here
probeDispatch.on(("probeLoad."+this.label), this.probeParse);
// this next line isn't working, but I don't know what to do
probeDispatch.probeLoad.apply(this);
};
genChart.prototype = {
probeParse: function(probeData, simTime) {
// How do I get the context from the object that's calling probeParse
// into the probeParse scope?
var self = this;
console.log(self.label);
}
};
var instanceOfGenChart = new genChart("pants");
function parse_dispatch(){
// send two arguments with my dispatch
probeDispatch.probeLoad.apply(instanceOfGenChart, [lines[line_count][0], lines[line_count][1]]);
line_count += 1;
if(line_count >= lines.length){
//line_count = 0
window.clearInterval(parse_timer);
}
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>
So it turns out to bring the context into the function, I have to bind() it for reasons I'm not too clear on.
// create my dispatcher
var probeDispatch = d3.dispatch("probeLoad");
var line_count = 0;
// load a file with a bunch of JSON and send one entry every 50 ms
var lines = [[0,1],[1,2],[2,0]];
var parse_timer = window.setInterval(
function () {
parse_dispatch();
}, 50
);
function parse_dispatch(){
// send two arguments with my dispatch
probeDispatch.probeLoad(lines[line_count][0], lines[line_count][1]);
line_count += 1;
if(line_count >= lines.length){
//line_count = 0
window.clearInterval(parse_timer);
}
}
// my chart object
var genChart = function(label){
this.label = label;
// assume I've drawn my chart somewhere here
probeDispatch.on(("probeLoad."+this.label), this.probeParse.bind(this));
};
genChart.prototype = {
probeParse: function(probeData, simTime) {
// How do I get the context from the object that's calling probeParse
// into the probeParse scope?
var self = this;
console.log(self.label);
}
};
new genChart("pants");
new genChart("shirt");
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>
Added by meetamit
Bind is the solution here, because it locks a scope to an "instance" of genChart.prototype. probeParse. This way parse_dispatch (the invoker) doesn't need to know anything about scope. It's equivalent to this:
// my chart object
var genChart = function(label){
this.label = label;
var self = this;
var probeParseBound = function() { self.probeParse(); };
probeDispatch.on(("probeLoad."+this.label), probeParseBound);
};

Get WebGL texture/buffer/shader count

Is there a way to get the count of the currently existing textures, buffers or shaders of a WebGL context? Like the numbers you can get in Firefox if you look at about:memory.
I'd like to check if all these are deleted successfully when my application closes.
There is no way to get that info directly from the WebGLRenderingContext but you could easily augment the context yourself something like
var numTextures = 0;
var originalCreateTextureFn = gl.createTexture;
var originalDeleteTextureFn = gl.deleteTexture;
gl.createTexture = function() {
++numTextures;
return originalCreateTextureFn.call(gl);
};
gl.deleteTexture = function(texture) {
--numTextures;
originalDeleteTextureFn.call(gl, texture);
};
You can write similar functions for other resources.
Of course if you want to be perfect you'd probably need to add a flag to each object just incase you try to delete something twice and also check the object passed in is actually the right kind. Something like
var numTextures = 0;
var originalCreateTextureFn = gl.createTexture;
var originalDeleteTextureFn = gl.deleteTexture;
gl.createTexture = function() {
++numTextures;
var texture = originalCreateTextureFn.call(gl);
texture.__deleted__ = false;
};
gl.deleteTexture = function(texture) {
if (texture && texture instanceof WebGLTexture && !texture.__deleted__) {
texture.__deleted__ = true;
--numTextures;
}
originalDeleteTextureFn.call(gl, texture);
};

How to check if a video is done playing

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')
}
}

EaselJS: BitmapSequence issue in a OOP-like class

I have been playing a bit with gskinner.com's EaselJS library (http://easeljs.com/, http://easeljs.com/examples/game/game.html), which makes dealing with HTML5's canvas a lot easier.
So I'm trying to remake something like Space Invaders in the canvas. So far it's not much, just the payer moving left to right. See the progress here: http://jansensan.net/experiments/easeljs-space-invader/
For the invaders, I needed an animation, so I followed a tutorial on how to do so: http://www.youtube.com/watch?v=HaJ615V6qLk
Now that is all good and dandy, however I follow gskinner.com's way of creating "classes": http://easeljs.com/examples/game/Ship.js I'm not certain if I can call that a class, but it is used as such.
So below is the class that I wrote for the Invader, however it seems like the BitmapSequence does not seem to be added to EaselJS's stage. Anyone can guide me through this? Thanks!
// REFERENCES
/*
http://easeljs.com/examples/game/Ship.js
*/
// CLASS
(function(window)
{
function Invader()
{
this.initialize();
}
var p = Invader.prototype = new Container();
// CONSTANTS
// VARS
p.image;
p.bitmapSequence;
// CONSTRUCTOR
p.Container_initialize = p.initialize; //unique to avoid overiding base class
p.initialize = function()
{
this.Container_initialize();
this.image = new Image();
this.image.onload = p.imageLoadHandler;
this.image.onerror = p.imageErrorHandler;
this.image.src = "assets/images/invader-spritesheet.png";
}
p.imageLoadHandler = function()
{
var frameData = {
anim:[0, 1, "anim"]
}
var spriteSheet = new SpriteSheet(p.image, 22, 16, frameData);
p.bitmapSequence = new BitmapSequence(spriteSheet);
p.bitmapSequence.regX = p.bitmapSequence.spriteSheet.frameWidth * 0.5;
p.bitmapSequence.regY = p.bitmapSequence.spriteSheet.frameHeight * 0.5;
p.bitmapSequence.gotoAndStop("anim");
p.addChild(p.bitmapSequence);
}
p.imageErrorHandler = function()
{
console.log("Error: the url assets/images/invader-spritesheet.png could not be loaded.");
}
window.Invader = Invader;
}(window));
Does you p.image/this.Container_initalize actually exist at that point? As you switch between using this. and p. between your init and other functions, while they might seem to be the same practice has often taught me its not the case. Try changing your init function to this:
p.initialize = function()
{
p.Container_initialize();
p.image = new Image();
p.image.onload = p.imageLoadHandler;
p.image.onerror = p.imageErrorHandler;
p.image.src = "assets/images/invader-spritesheet.png";
}

Categories