p5 canvas static after being cloned - javascript

Following instructions from this question, I have a div which is being cloned that has a p5 canvas inside it. When it is cloned the canvas is not responsive to mouse coordinates.
How do I make the p5 canvas still active after cloning?
$(document).ready(function() {
$(".showcanvas").click(function() {
// Find the original canvas element
var origCanvas = $(".canvas").first().find('canvas')[0];
// Clone the div wrapper
var clonedDiv = $(".canvas").first().clone(true);
// Find the cloned canvas
var clonedCanvas = clonedDiv.find('canvas');
// Update the ID. (IDs should be unique in the document)
clonedCanvas.prop('id', 'defaultCanvas' + $(".canvas").length)
// Draw the original canvas to the cloned canvas
clonedCanvas[0].getContext('2d').drawImage(origCanvas, 0, 0);
// Append the cloned elements
clonedDiv.appendTo("article").fadeIn('1200');
});
});
https://jsfiddle.net/vanderhurk/12fxj48h/28/

I was going to comment on your previous question about this. The approach you're taking of cloning the canvas element and then drawing the old canvas into the new canvas is going to have exactly this problem: the new canvas is not going to change as the old canvas changes. This might work if you just want to take a snapshot (although there are easier ways to do this), but my guess is it's not what you're looking for.
Instead of cloning the element and dealing with JQuery, I suggest you look into using instance mode from the P5.js library. You can read more about instance mode here, but basically it allows you to package your P5.js code in a self-contained object.
Here's a simple example:
var s = function( sketch ) {
var x = 100;
var y = 100;
sketch.setup = function() {
sketch.createCanvas(200, 200);
};
sketch.draw = function() {
sketch.background(0);
sketch.fill(255);
sketch.rect(x,y,50,50);
};
};
var myp5 = new p5(s);
If I were you, I would encapsulate the creation of an instance-mode P5.js sketch into a function or class. Then whenever I want to create a new copy of the sketch, I'd call that function or class. You could also store any shared state in global variables that both sketches access.

Related

Functions, and Image importing

I'm working on a project in game development in Javascript and HTML5 canvas. I have this common code I use for loading sprites:
var sprite = new Image();
sprite.src = "sprite.png";
I was wondering if there was a simpler way to do this, which I first thought by function, but not sure how I should do so. I would think to do so like this:
function loadSprite(src) {
this.src = src;
}
var loadSprite(sprite.png);
However I don't think this is the right way to do it. Could someone correct my code and/or give a simpler way of loading an image like this? (I am also using a ctx.drawImage(..., sprite) in order to change coordinates on the canvas so it needs an x,y,width,and height parameters in one way or another)
Why not use as below:
function loadSprite(src) {
var sprite = new Image();
sprite.src = src;
return sprite
}
var _local_var = loadSprite('sprite.png');

HTML5 Canvas: Setting context on resize

I have a project using HTML5 Canvas (createjs) and I've had issues with spikes on text strokes, meaning I have to set the miterlimit of the 2d context. However, the parent (which I have no control over) scales the canvas when the window is resized, which obviously resets the canvas context.
Now, I want to avoid putting an onresize event inside the client - my first thought is just to use the createjs Ticker thus:
createjs.Ticker.addEventListener("tick", handleTick);
function handleTick(event) {
var ctx = canvas.getContext('2d');
ctx.miterLimit = 2;
}
Though this seems a little wasteful, is there a more efficient way of doing this, without using DOM events?
Your approach might work, but its definitely a hack, since you can't expect that context properties will be maintained, or that they won't be applied in the wrong place.
If you do want to patch the display list to update the context, you can use the "drawstart" event, which fires before the display list is drawn:
stage.on("drawstart", function(e) {
var ctx = stage.canvas.getContext("2d");
ctx.miterLimit = 2;
});
However if you want a better approach that is instance-specific, you can extend the Text class to append any context properties you want. Here is a quick example where miterLimit is stored and applied any time the text is drawn. In this example, you can create multiple instances and set different miter limits on them. Note that you might want to also support other properties such as lineJoin.
http://jsfiddle.net/cr4hmgqp/2/
(function() {
"use strict"
function MiterText(text, font, color, miterLimit) {
this.Text_constructor(text,font,color);
this.miterLimit = miterLimit;
};
var p = createjs.extend(MiterText, createjs.Text);
p.draw = function(ctx, ignoreCache) {
ctx.miterLimit = this.miterLimit;
if (this.Text_draw(ctx, ignoreCache)) { return true; }
return true;
};
p.clone = function() {
return this._cloneProps(new MiterText(this.text, this.font, this.color, this.miterLimit));
};
createjs.MiterText = createjs.promote(MiterText, "Text");
}());
Note that this issue should hopefully be fixed in the next version of EaselJS. Here is the tracked issue: https://github.com/CreateJS/EaselJS/issues/781
Cheers.

cocos2d js 3.7 runScene issue

So i am porting my game from cocos2d c++ to js and sorted lots of js related differences already, but can not understand nor find online the solution to particular problem involving switching of the scenes with the cc.director.runScene().
So i have a complex game scene which i load like that:
cc.LoaderScene.preload(gameplay_resources, function () {
cc.director.runScene(new GameScene(level, epoch));
}, this);
Which takes stage and level params and returns the scene object which contains all the gameplay elements.
Fragment of Game scene looks like this:
var GameNode = cc.Node.extend({
levelID:null,
epoch:null,
platforms:null,
boardSize:null,
numberOfMovesLeft:null,
numberOfMovesAllowed:null,
sessionInfo:null,
ctor:function (levelID, epochID)
{
this._super();
this.levelID = levelID;
this.setEpoch(Epoch.epochForNumber(epochID));
this.platforms = [];
var self = this;
var gameplayUI = ccs.load(gameplayRes.GameplayUI, "res/");
this.addChild(gameplayUI.node);
var replayButton = gameplayUI.node.getChildByName("replay");
cc.assert(cc.sys.isObjectValid(replayButton), "Replay button not valid");
replayButton.addTouchEventListener(function (sender, type) {
if(type != ccui.Widget.TOUCH_ENDED) return;
cc.LoaderScene.preload(gameplay_resources, function () {
cc.director.runScene(new GameScene(self.levelID, self.epoch.ID));
}, this);
}, this);
return true;
}
//... Other methods
});
var GameScene = cc.Scene.extend({
ctor:function (levelID, epochID) {
this._super();
var gameNode = new GameNode(levelID, epochID);
this.addChild(gameNode);
}
});
All works fine in the end in the scene itself, but say if i change the scene by the same method to main menu, and then go to gameplay again, it seems as the 'new' game scene object has previous (supposed to be released) object`s values. So if i press 'Replay' button, it uses the old game scenes values as well.
I mean in C++ when you replace scenes, old scene`s memory is released by cocos engine. And if you go to that scene by creating new object - its new.
So my question is why is that happening i js? Maybe i do not know something about cocos2d js memory management so i need to do something extra to release old scene?
What i have ensured:
When i extend the engines classes all my added variables a null'ed and objects values are assigned in ctor's using this.value = ...; not to have static values for all objects in that way.
There are no children retaining the Gameplay scene (or it seems not to be) so i am assuming it should be released when i replace scene?
I am not using retain()/release(), and all children are added to the gamescene to be retained.
Any suggestions would be appreciated.
Cheers!
So i have solved it - i was using event manager therefore sending events and game scene with its children have been registered for some of them. I was assuming that eventManager retains nodes on a 'weak' basis, but it seems you have to call removeListeners() for each registered node in its onExit method to remove listeners manually. So now it seems to be working fine.

Raphael js drag inside javascript object

I had a little problem today and thought I could try stack overflow. I'll be short and sweet (I removed lot of code to make this clear).
I recently discovered raphaeljs and I like it.
I make some circle draggable and it works fine like this:
Working script:
<script>
var paper = Raphael(100,100,500,500);
var circ = paper.circle(50,50,10)
var start = function(){ };
var move = function(dx,dy)
{
this.attr({cx: this.ox + dx, cy: this.oy + dy});
};
var up = function(){};
circ.drag(move,start,up);
<script>
Ok fine, it works and all functions are called properly!
BUT!
I want my move ,start ,up functions to be inside an object and not in the main page
SO
here's my next code
<script src="myobject.js"></script>
<script>
var paper = Raphael(100,100,500,500);
var myobj = new myobject("12","12","6");
<script>
Content of myobject.js :
function myobject(vx,vy,vr)
{
var x,y,r;
x=vx;y=vy;r=vr
paper.circle(x,y,r);
var start = function(){};
var move = function(dx,dy){};
var up = function(){};
this.drag(move,start,up); // error here this line crash
}
I cannot find how to use the drag function inside my object to make it draggable.
Well, that's it. I hope I've been clear and pardon me if there's anything wrong with the way I made this post but it is my first one!
Thanks to everyone that will try to help me!
Wilson
Inside myobject, this variable points to this object, and not to Raphael circle. As myobject does not have drag function, the code yields an error. To make it work, you must refer to Raphael object that has to be dragged, i.e.
function myobject(vx,vy,vr) {
...
this.circle = paper.circle(x,y,r);
...
this.circle.drag(move,start,up);
...
}
Fine, #Hubert OG was right but I also had to change the way I declared my function from
var start()=function
to
this.start() = function
WARNING: Fill your circle/forms because if you don't you have to click the fine border to move it around.

Lock/unlock HTML5 canvas

Is there any possibility of locking canvas element? In my app I draw complex images and sometimes I use bitmaps. Using bitmaps with canvas isn't quite comfortable - all the drawing that should be placed on canvas after bitmap is placed in bitmaps .onload.
It would be a lot easier if I could lock and unlock canvas so it couldn't be updated for some time.
AFAIK there is no built-in function for lock/unlock. Do you know any simple way of implementing it?
I don't know whether this is bulletproof or not, but you could temporarily make .stroke etc. noops: http://jsfiddle.net/eGjak/247/.
var toLock = "stroke fill".split(" ");
function lock() {
$.each(toLock, function(i, name) { // or another way to loop the array
ctx[name] = function() {};
});
}
function unlock() {
$.each(toLock, function(i, name) {
ctx[name] = ctx.constructor.prototype[name];
});
}
$("canvas").attr("disable","False");
// bitmap .onload...
$("canvas").attr("disable","True");
Or
bitmap.onload = function(){
var canvas = window.getCanvas();
});

Categories

Resources