I am adding a canvas to the DOM, and then using CreateJS to build a game. I am initialising a CreateJS ticker, and adding animations and graphics.
Everything works fine, but only once. If I remove the canvas and the game code, I can't add it again later on - the canvas just doesn't show anything anymore.
My question: how do I properly clear all CreateJS functions from memory, and start anew with a new canvas? It seems that CreateJS keeps holding on to old listeners and elements, even though I removed everything.
This is my code:
// remove canvas and then restart - this causes buggy behavior
this.removeAndRestart = function() {
document.getElementById("gamecontainer").innerHTML = '';
createjs.Ticker.removeAllEventListeners();
setTimeout(this.showGame, 1000);
}
// simply start the game - this works only the first time
this.showGame = function() {
document.getElementById("gamecontainer").innerHTML = '<canvas id="gamecanvas" width="900" height="400"></canvas>';
this.stage = new createjs.Stage("gamecanvas");
// create the ticker and update the stage
createjs.Ticker.setFPS(30);
createjs.Ticker.addEventListener("tick", tickHandler);
}
If you are changing canvases, or resetting the stage, make sure to remove the DOM events from the stage. From the docs:
enableDomEvents(Boolean enable)
Enables or disables the event listeners that stage adds to DOM elements (window, document and canvas). It is good practice to disable events when disposing of a Stage instance, otherwise the stage will continue to receive events from the page.
When changing the canvas property you must disable the events on the old canvas, and enable events on the new canvas or mouse events will not work as expected. For example:
myStage.enableDOMEvents(false);
myStage.canvas = anotherCanvas;
myStage.enableDOMEvents(true);
http://www.createjs.com/Docs/EaselJS/classes/Stage.html#method_enableDOMEvents
I am not sure if this will solve your problem, but it could help.
i recommend you to use this
//create listener tick
createjs.Ticker.addEventListener('tick',tick);
//remove listener tick
createjs.Ticker.removeEventListener('tick',tick);
//exemple stopped object moves in Y axe if it exceeds heigth of canvas
createjs.Ticker.addEventListener('tick',tick);
function tick(){
console.log( myBitmap.x +" "+myCanvas.width);
if (myBitmap.y < myCanvas.height){
myBitmap.y=myBitmap.y+10;
}else{
createjs.Ticker.removeEventListener('tick',tick);
}
scene.update();
}
Related
I am trying to verify that this happens no matter what, and there's no way to bypass it. It seems pretty silly to me that createjs uses this architecture. But I noticed that creating a stage from an existing canvas element removes all shapes, writings, etc from the canvas? Code is below:
html:
<canvas id="canvas" width="800" height="400"></canvas>
js:
var canv = document.getElementById("canvas");
var stage = new createjs.Stage(canv);
var ctx = canv.getContext('2d');
ctx.beginPath();
ctx.arc(50,50,10,0,2*Math.PI);
ctx.stroke();
createjs.Ticker.addEventListener("tick", tick);//circle created is overwritten here!!!?! Why createjs!?
//stage.update();
createjs.MotionGuidePlugin.install();
var shape1 = new createjs.Shape();
shape1.graphics.f("#000000").dc(0,0,10);
var path1 = new createjs.Shape();
path1.graphics.beginStroke("#ff0000").mt(0,0).qt(50,100,100,0);
stage.addChild(path1, shape1);
createjs.Tween.get(shape1).to({guide:{ path:[0,0, 50,100, 100,0] }},2000, createjs.Ease.cubicInOut);
function tick(event) {
stage.update();
}
Is this something that cannot be bypassed? It seems silly to me that createjs wouldn't just actually use the existing element unerased. If not, what is the point in passing in an element in the first place, why doesn't it just create a canvas element, and give you the ID? Anyways, if this is how it's going to be, unfortunately, I am going to have to go somewhere else. Sad, because createjs seemed pretty useful.
CreateJS uses a retained graphics mode, that is, it stores the state and redraws it each time. This is because the canvas is basically a big Bitmap with drawing commands – clearing the stage is the only way to remove the previous state.
But good news! There are lots of ways to get around these limitations if you want to blend CreateJS content with other content, or even make additive drawing effects.
The first is easy, which is setting autoClear. This will prevent the clear, and just draw the new contents over the old one.
stage.autoClear = false;
The second is a bit tougher, but great for instances where you want to mix CreateJS content with other libraries or effects. You can basically use the other canvas as the source to a Bitmap you include in CreateJS:
// Create a child for CreateJS referencing the other canvas
var bmp = new createjs.Bitmap(otherCanvas);
// Add it at the bottom (or top or wherever) in your new CreateJS canvas
stage.addChildAt(bmp, 0);
This is a great approach because it lets you put your content wherever you want, edit it separately, etc.
If you have a different case this doesn't cover, let me know and I can try to make a recommendation!
Cheers.
I have a Konva stage that currently displays a series of shapes. I would like to have a shapes panel, where I can drag shapes and insert into the canvas.
There are currently two ways of doing this:
Adding the Shapes Panel to the Konva stage as it's own layer and entity
Having the Shapes Panel as a standalone HTML element outside the Konva stage and implement a draggable js library to handle dragging behaviour
I'd rather option 2; being able to style the shapes panel with CSS and yield a number of other DOM related benefits is more attractive to me right now.
I have the dragging behaviour sorted, but there is one issue: even though I've implemented stage mouseover events, dragging an element that originates from outside the canvas to on top of the canvas doesn't actually trigger the stage event listeners.
Is there a way around this?
What's interesting is that if you click and hold the mouse outside the element and hover over the canvas, the event listeners fire. But, when you're actually dragging an element (text, image), the event listeners do not fire...
Take a look into this demo: https://konvajs.org/docs/sandbox/Drop_DOM_Element.html
var con = stage.container();
con.addEventListener('dragover', function(e) {
e.preventDefault(); // !important
});
con.addEventListener('drop', function(e) {
e.preventDefault();
// now we need to find pointer position
// we can't use stage.getPointerPosition() here, because that event
// is not registered by Konva.Stage
// we can register it manually (with private method):
stage.setPointersPositions(e);
// now you can add a shape. We will add an image
Konva.Image.fromURL('/assets/yoda.jpg', function(image) {
layer.add(image);
image.position(stage.getPointerPosition());
image.draggable(true);
layer.draw();
});
});
Long time lurker but never made an account. Just wanted to preface that I'm by no means a dev and just tinkering and experimenting for fun, so I apologise in advance if I seem really dumb.
I'm working on a dynamic overlay for Twitch streaming and was previously using AS3 but I've switched over to HTML5 now. I'm trying to load an image onto the canvas (which will eventually be a profile picture fetched using Twitch API... but one step at a time). I'm using Adobe Animate and I have the following so far applied in Actions on the first frame of the layer:
var canvas = document.getElementById('canvas'),
context = canvas.getContext('2d');
show_image();
function show_image() {
source_image = new Image();
source_image.src = 'https://cdn.sstatic.net/stackexchange/img/logos/so/so-icon.png';
source_image.onload = function () {
context.drawImage(source_image, 100, 100);
}
}
When I hit Ctrl+Enter and see it in Chrome, the image appears for the first frame then disappears. I'm not sure how I'm supposed to get it to stay indefinitely. I need to be able to animate it later, and it'll change depending on the latest follow/donation/sub, etc.
I tried extending the frame itself in the timeline, however, this just changed long how it took to loop and didn't make the image itself stay longer. I'm probably missing something really simple!
Any help would be appreciated. Thanks!
Your code is okay if your approach is using a canvas with HTML and JS, without any libraries involved. However, this is not the case, as you are using Animate, and the way to draw graphics with it is different than using default canvas methods like drawImage().
Animate includes the CreateJS suite, which includes the EaselJS library ,and this allows you to use another tools to draw to your canvas. Two or them are the Stage object, the visual container of your animate project, and the Bitmap object, who represents an image, canvas or video. For effects of this question, only both objects are required.
Note that the code below is only for the first frame:
/* It is not necessary to declare the canvas or stage element,
as both are already declared. At this point the stage is ready to be drawn */
show_image();
function show_image() {
var source_image = new Image();
source_image.src = 'https://cdn.sstatic.net/stackexchange/img/logos/so/so-icon.png';
source_image.onload = function(event) {
/* A new Bitmap object is created using your image element */
var bmp = new createjs.Bitmap(event.currentTarget);
/* The Bitmap is added to the stage */
stage.addChild(bmp);
}
}
I have the following problem:
I create a Raphael canvas in a div. This happens as soon as the page is loaded and the initRadar() function is called:
var r;
var paper;
var c;
function initRadar(){
r = $( "#circ" );
paper = Raphael("circ", r.width(), r.height());
c = paper.circle(r.width()/2, r.height()/2, r.height()/2-2);
$(window).on("orientationchange",function(){
//redraw(); // <--- the way I wanted it
setTimeout(function(){ redraw(); }, 300); // <--- *yuck*
});
}
This functions perfectly so far. My problem starts when the orientation of the viewport changes. I thought I could add an event handle to the window, which fires, when the orientation changes and redraw the content. And it works... kind of. I wanted to call the second function:
function redraw(){
c.remove();
c = paper.circle(r.width()/2, r.height()/2, r.height()/2-2);
}
Whenever the orientation changes, this function redraws the content. And this also works... almost. The problem is, I have a race condition. Even though the orientation change event fired, the #circ div still has the old size and position. This leads to the strange effect, that when the viewport is in portrait mode, the landscape circle is drawn and vice versa.
My current solution is to use the timeout function (yuck), to wait a few ms so that the layout is done before I draw the circle. It works, but it is ugly and I don't want to have such a hack in my code.
Can someone point me in the direction how to solve this problem correctly?
I'm working in a tool to draw in a canvas using the framework Paper.js
I got an issue using iPad. When I'm drawing with one finger, that works. When I'm drawing with two fingers, one in the canvas and one outside the canvas, the second finger event is caught by the event onMouseDrag, and that put some stroke from the first finger to the second finger, not a good behaviour for me.
Example:
At the beginning, I start to draw with one finger. After I put the second finger outside the canvas and I continue to move my first finger. This is what happen.
Do you have any idea to avoid event when I'm outside the canvas?
Thanks.
If you don't want the finger outside to be detected, limit the target to your canvas.
var canvasElement = document.getElementById('canvasId') //or element
tool.onMouseDrag = function(event) {
if (event.event.target === canvasElement) { //my target canvas was nested like this
path.add(event.point);
path.smooth();
}
}
Well, you could test event.point.isInside(view.bounds). This will likely kill your performance if you test it while drawing, but you could cull the points after you're finished.