removeChild() not working using easeljs - javascript

I am using easeljs to create a stage and then i am putting tiles on the stage on random locations. When the user clicks on a tile, the tile must be removed from the stage.
There are two problems that i am facing. First was that the mouse event was not working. The code "tile.onPress = (tileOnPress).bind(this);" so i used the addEventListener method instead. Now although the function is being called as i am getting the output on the console, the tile is not being removed from the stage.
Here is the code:
c99.Game = (function(){
function Count99Game() {
console.log("Count 99 game starts");
this.canvas = document.getElementById('game-canvas');
this.stage = new createjs.Stage(this.canvas);
var totalTiles = 10;
var tileOnPress = function(event) {
console.log("Pressed");
this.stage.removeChild(event.target);
this.stage.update();
};
for (var i = totalTiles; i > 0; i--) {
var tile = new c99.Tile(i);
this.stage.addChild(tile);
tile.x = Math.random()*(this.canvas.width - tile.width);
tile.y = Math.random()*(this.canvas.height - tile.height);
//tile.onPress = (tileOnPress).bind(this);
tile.addEventListener("click", tileOnPress.bind(this));
}
this.stage.update();
}
return Count99Game;
})();
I would appreciate if someone could tell me why "tile.onPress = (tileOnPress).bind(this);" isn't working and also what changes need to be done in the tileOnPress function so that the tile that is pressed can be removed from the stage.
The complete code can be found at https://github.com/ZANTGames/count99/blob/master/js/count99-game.js

Try this
this.stage.removeChild(event.target.parent)
This is because event.target is shape and its parent is tile and basically you want to remove the tile so this is working
For your future reference I have found it from this documentation
http://www.createjs.com/docs/easeljs/classes/Stage.html

Related

How to remove bitmap image on click from canvas

I am using createjs as my framework. I've placed a Bitmap on the canvas and I created a function to try and remove it but I keep getting an error message in the console that image is not defined. This is what my code looks like:
// onload=init() called in html doc
function init(){
var canvas = new createjs.Stage("canvas");
// Add image to canvas
image = new createjs.Bitmap("image.png");
image.x = 200;
image.y = 180;
image.scaleX = 0.35;
image.scaleY = 0.35;
canvas.addChild(image);
image.addEventListener('click', pop);
canvas.update();
}
//remove image from canvas
function pop() {
console.log('pop');
canvas.removeChild(image);
}
When I click on it, I get the console message "pop" followed by the error I mentioned above. I've tried moving the function inside init but I appear to get the same problem.
Make image as global variable, so that it can be accessed by all the functions in your case function pop.
var image;// defining 'image' variable as global
function init(){
var canvas = new createjs.Stage("canvas");
// Add image to canvas
image = new createjs.Bitmap("image.png");
image.x = 200;
image.y = 180;
image.scaleX = 0.35;
image.scaleY = 0.35;
canvas.addChild(image);
image.addEventListener('click', pop);
canvas.update();
}
//remove image from canvas
function pop() {
console.log('pop');
canvas.removeChild(image);
}
This is a scope issue. You defined image inside your init function, so it is not accessible on the pop method.
There are two easy fixes. Either move the var image outside of the init function, or use the click target instead.
var image;
function init() {
init = new createjs.Bitmap();
// etc
}
// OR
function pop(event) {
stage.removeChild(event.target);
}
Scope is really important to understand when building JavaScript applications, so I suggest getting to know it a little better :)
Cheers,

FabricJS ClipTo Issue for multiple objects like group

My code is
canvas.clipTo = function (ctx) {
ctx.beginPath();
for (var i = 0; i < totalPrintArea; i++) {
ctx.save();
ctx.fillStyle = 'rgba(51,51,51,0)';
ctx.rect(clipLft[i], clipTp[i], clipW[i], clipH[i], 'rgba(51,51,51,1)', clipRtn[i]);
ctx.stroke();
ctx.restore();
}
ctx.closePath();
ctx.clip();
canvas.calcOffset();
};
canvas.renderAll();
I am taking values from the red dotted box and apply to clip where multiple masks are generating.
My issue is its taking all properties but not rotation for all.
I want to rotate all the rectangles.
I just get some code to change the rotation for the clip like ctx.rotate(50); but will not work as I want to make all rotate with their own values
Please guide me for the same.
On the original fabricJS github project I saw the comment: https://github.com/kangax/fabric.js/issues/932#issuecomment-27223912
and decided that I need to prevent making ctx.beginPath all the time:
canvas.clipTo = function(ctx) {
var skip = false;
// Workaround to make possible
// making clipTo with
// fabric.Group
var oldBeginPath = ctx.beginPath;
ctx.beginPath = function() {
if (!skip) {
oldBeginPath.apply(this, arguments);
skip = true;
setTimeout(function() {
skip = false;
}, 0);
}
}
group.render(ctx)
};
You can see my workaround to the problem described:
https://jsfiddle.net/freelast/6o0o07p7/
The workaround is not perfect, but hope it will help somebody.
I have tried using the Andrey's answer, but althouth there some interesting points, it didn't work.
If you try to clip the canvas to a single object (e.g. a circle or a rectangle), you can simply do this:
canvas.clipTo = function(ctx) {
shape.render(ctx); //shape is a circle, for instance
}
However, as explained by Kienz and butch2k in the aforementioned comment on GitHub, the problem is that you cannot use this solution with groups. In particular, if you use the following snippet:
canvas.clipTo = function(ctx) {
group.render(ctx);
}
you will only see one object of the group to be used for clipping.
The issue is due to the render method, which calls the ctx.beginPath() and ctx.closePath() for each object in the group. And because only the last couple of beginPath-closePath calls will affect the clipping, you need some workaround.
So in my solution, I have temporarily redefined the ctx.closePath and ctx.beginPath methods (after storing them in other two temporary variables, named oldBeginPath and oldClosePath) so that they do nothing. Then I call oldBeginPath at the beginning, and after rendering all the objects in the group I call the oldClosePath.
And now, here is the (working) snippet:
canvas.clipTo = function(ctx) {
var oldBeginPath = ctx.beginPath;
var oldClosePath = ctx.closePath;
ctx.beginPath = function() {}
ctx.closePath = function() {}
oldBeginPath.apply(ctx);
group.forEachObject(function(shape){
shape.render(ctx);
});
oldClosePath.apply(ctx);
ctx.beginPath = oldBeginPath;
ctx.closePath = oldClosePath;
};
Hope this will save someone's spare time in the future.

Reading prototype variable with easeljs click event [duplicate]

This question already has an answer here:
EaselJS: Can somebody explain the inheritance pattern used in demos?
(1 answer)
Closed 9 years ago.
I'm quite new to JS's prototypying but not to oop in general. New to easeljs, however.
Having said that, i've been trying to get an object variable triggered by a click event, and i REALLY can't seem to find a decent way of doing it.
Trying to build a clickable 2D "board", here is my test code:
(function() { //"Class"
Brick = function() {
this.initialize();
};
var p = Brick.prototype = new createjs.Container();
p.Container_initialize = p.initialize;
p.initialize = function() {
this.Container_initialize();
};
p.create = function(row, column) {
this.row = row;
this.column = column;
//Shape
this.square = new createjs.Shape();
this.square.graphics.beginFill("green").drawRect(0, 0, brickSize, brickSize);
this.x = (brickSize * column) + (Game.padding * column); // Add some padding
this.y = (brickSize * row) + (Game.padding * row); // Add some padding
this.addChild(this.square);
this.addEventListener("click", function(event) { console.log(this.row)})
};
})();
After this I just create a few Bricks cycling through a multidimensional array cycle, and add them to the stage. The board shows perfectly, however, i keep getting "undefined" while cliking. console.log(event.currentTarget.row) works though, but not sure it's the way to go.
Thanks!
It's better not to create an instance of Parent to set the prototype of Child, use Object.create and shim it for older browsers:
var p = Brick.prototype = Object.create(createjs.Container.prototype);
Your event handler has the wrong value for this. The this value is the invoking object and is determined when invoking the function not when declaring it. You can fix that in the following way:
p.create = function(row, column) {
//.... not changed
var me = this;
this.addEventListener("click", function(event) {
console.log(me.row)})
};
If you use Chrome or Firefox with firebug it's sometimes better to just console.log(this) and click on the logged item for closer inspection.
More info about prototype can be found here.

Load stage with all elements in kineticjs

I try load my simple stage from json file, I load images but it's all in one layer, and image is not in group, so resize not working, i don't know how i should to load all elements with layers and group;
This is my function to load(it's only image for now)
function load(loadStage) {
counter = 2;
activeStage = stage;
stage = Kinetic.Node.create(loadStage,'right');
var background = stage.get('.background');
var backgroundImage = stage.get('.backgroundImage');
var clipartsImage = stage.get('.image');
var text = stage.get('.text');
console.log(stage.getChildren());
for(i=0;i<clipartsImage.length;i++){
counter++;
(function() {
var image = clipartsImage[i];
groups[counter] = image.parent.get;
//console.log(image);
var imageObj = new Image();
imageObj.onload = function() {
imageObj.src = image.attrs.src;
console.log(image);
image.setImage(imageObj);
image.on('mouseover', function() {
document.body.style.cursor = 'pointer';
});
image.on('mouseout', function() {
document.body.style.cursor = 'default';
});
image.on('click', function(evt) {
this.children[0].children[3].show();
var shape = evt.targetNode;
this.moveToTop();
active = layers[shape.getId()];
objectId = shape.getId();
});
image.getLayer().draw;
};
imageObj.src = image.attrs.src;
})();
stage.draw();
}
stage.draw();
}
And this is my json file, http://wklej.org/id/1105520/ this is middle stage. I'll keep trying, but if someone has had a similar problem and solved it, I would be grateful for your help :)
1)
What is going on with your JSON file? the base64 string has blown up into a million lines...
For starters, KineticJS.Layer cannot have a layer as a child. References:
https://github.com/ericdrowell/KineticJS/wiki/Change-Log#455-july-28-2013
new add() validation. An error is thrown if invalid children are added to a parent, for example, when adding a layer to another layer.
https://github.com/ericdrowell/KineticJS/wiki
KineticJS event not fired for child of a grouped layer
Inside your JSON file, you have tons of layers layered within each other, this is definitely going to cause a problem. Actually it looks like you have a layer for EACH group that you have! This is completely wrong KineticJS structure.
You should do some research on how and when to use layers and groups, here are some references:
What are the differences between group and layer in KineticJs
https://github.com/ericdrowell/KineticJS/wiki (again, the data structure hierarchy for KineticJS)
2)
No need to call stage.draw() twice.
3)
JSON is a data format, it only stores object attributes. This means it does not store any references to events attached to objects.
What this means is that when you load your JSON string, you'll have to rebind the updateAnchor function to all your anchors again. (Similar to how you are rebinding click function to your images onload)
You'll have to do something like this inside your load function, after you create the stage with your JSON file:
var children = layer.getChildren(); //Use the layer that has all your groups with images/anchors. *REMEMBER you can't layers within layers!
for (var i=0; i<children.length; i++) {
//If name starts with 'anchor'
if (children.getName().indexOf('anchor') !== -1) {
children[i].on('dragmove', function(evt) {
updateAnchor(this);
layer.draw();
});
}
}

Is it possible to have multiple KineticJS animations on a single layer?

I have a problem getting my KineticJS animations to stop().
I have three KineticJS image objects on the same layer, and I have added a KineticJS animation to each of those KineticJS image objects. However only one of the image objects shows any animation. It also won't stop animating in response to anim.stop(), unless I stop() the animations for all three objects (including the ones which are not actually visually animating).
My question is: is it even possible to add multiple independent animations on seprate objects/images/shapes to a single layer and still be able to start() / stop() each animation individually? Or do I need to create an individual layer for each KineticJS image object?
In a nutshell (hacked down version), my code is as follows:
stage = new Kinetic.Stage({container: "container", width: windowWidth, height: windowHeight});
layer = new Kinetic.Layer();
var kinObjArr = [];
for (var i=0; i < 3; i++) {
kinObjArr[i] = new Kinetic.Image({image: myHTMLImage});
kinObjArr[i].anim = new Kinetic.Animation({
func: function(frame) {
kinObjArr[i].setX(30 * Math.sin(frame.time * 2 * Math.PI / 500) + 100);
},
node: layer
});
kinObjArr[i].anim.start();
kinObjArr[i].on('touchstart', function(){
this.anim.stop(); // <----- Doesn't stop
layer.draw();
});
} // for
stage.add(layer);
Basically only the last KineticJS image in the list will be animated and it can only be stopped when all 3 images have been touched/clicked.
classic closure problem. you need to use an anonymous function to induce scope, or break out all of your logic into its own function. Here's an article about Javascript closure:
How do JavaScript closures work?
KineticJS supports an unlimited number of Animations (until of course, you run out of memory)
Thanks for the response Eric. I read that article and it bent my head out of shape, but I think I got it in the end. I choose your second option and it works like a charm:
(again, this is a hacked version of my actual code, haven't tested this snippet)
stage = new Kinetic.Stage({container: "container", width: windowWidth, height: windowHeight});
layer = new Kinetic.Layer();
var kinObjArr = [];
function myFunc(i) {
kinObjArr[i] = new Kinetic.Image({image: myHTMLImage});
kinObjArr[i].anim = new Kinetic.Animation({
func: function(frame) {
kinObjArr[i].setX(30 * Math.sin(frame.time * 2 * Math.PI / 500) + 100);
},
node: layer
});
kinObjArr[i].anim.start();
kinObjArr[i].on('touchstart', function(){
this.anim.stop(); // <----- Stops now
layer.draw();
});
} // function myFunc
for (var i=0; i < 3; i++) {
myFunc(i);
} // for
stage.add(layer);

Categories