Is Canvas' drawImage method truly syncronous? - javascript

I'm implementing a menu system for my game using canvas (for certain performance reasons I cannot use HTML/CSS to make the menus). I have the menu configured using JSON and menuComponent objects are created with their respective properties (x, y, width, height, imagePath, etc). I have a menu loader which then iterates over the component objects and calls the componentObjects' draw method (all images wait for their onload event to fire first, of course).
Anyway, I expect my images to be drawn in the order that their draw method is called so that they overlap in the correct order. The majority of the time this behaviour is correct but occasionally they will draw in the wrong order.
My question is - can I trust Canvas to draw images in the order the drawMethod is called for those images? Say I have image A which is, for example, 10MB and image B which is 10kb. If I call draw image A and then draw image B then is there a chance that image B will load first because it's a smaller image?
I was trying to be smart with my code (having nested components inside my component objects and recursively call draw methods) so it's possible there's some race conditions in my code, I just want to confirm the above behaviour is correct. If I add logic to force my objects to wait until a ready flag is set then it seems to work. But unfortunately that slows up my menus load time.

To put a formal answer to this post -
In the end I simplified my solution to use one menuLoader object which has an array of hashes for each image to be drawn (containing x, y, imagePath, ready flag). I call a create components method which builds up these hashes with the ready flag set to false by default. I set an onload event for each image to set its respective ready flag to true.
After create components has finished executing I use setInterval to spin until all flags have been set to true. Once this condition is met I iterate through my array of hashes again and call the draw method for each image.

Man I've faced same problem and have been stucked with it for about three days. And I figured one interseting thing. Please look though this code snippet and supply me with your thoghts on it.
final ResourceManager rm = new ResourceManager(1000, 1000);
rm.loadImgResource(LandCardResources.INSTANCE.getMeadow(), "meadow", 0, 0);
rm.loadImgResource(LandCardResources.INSTANCE.getHellHorseKnight(), "knight", 150, 150);
Resource manager is an object representing BackBufferCanvas that holds all images in its context (like simple image sprite). Constructor is also responsible for adding this Backbuffer to RootPanel, so we can determine thats everything worked like we expected. After that I'm adding my main canvas to root trying to draw on it from backBufferCanvas using perfectly working ResourceManager instance.
canvas.setWidth(500 + "px");
canvas.setHeight(500 + "px");
canvas.setCoordinateSpaceWidth(500);
canvas.setCoordinateSpaceHeight(500);
RootPanel.get().add(canvas);
rm.drawImageFromMetaDb(ctx, 0, 0, 100, 100, 0, 0, 100, 100);
rm.drawImageFromMetaDb(ctx, 150, 150, 100, 100, 50, 50, 100, 100);
And it never works. But if I for example add Button to rootPanel with handler that is responsible for rm.drawImage..... It will work perfectly when clicking this Button. Can't really understand why this is happening as backBufferCanvas is attached before mainCanvas so logic must be already delayed.

Related

Canvas rendering once, after all actions

A little confused with one moment, appreciate any help.
I'm making an app, that uses canvas for rendering game board.
And I faced a problem that its not optimal, rendering canvas for each little change.
Here's what the structure is at the moment:
function renderCanvas() {
// calling for each row
}
function renderRow() {
// calling for each cell
}
function renderCell() {
// Here i use FillRect and StrokeRect both
}
Functions cooperate with passing context to each other.
Now it renders each cell. And using beginPath appears to deal only with stroke.
I wonder if i can startPath (like beginPath) somehow in renderCanvas function and after all operations with context are done - i could render that all once?
You can only do one styling per beginPath...
So if your cells require different colors, fonts, opacities then you must do a beginPath for each different style (but you can group same-styles together into one beginPath).

Rendering multiple objects in WebGL

I have tried following the suggestions given as answer to this questions but I still can't figure out how the "rendering flow" of a WebGL program really works.
I am simply trying to draw two triangles on a canvas, and it works in a rather non-deterministic way: sometimes both triangles are rendered, sometimes only the second one (second as in the last one drawn) is rendered.
(it appears to depend on rendering time: strangely enough, the longer it takes, the better the odds of ending up with both triangles rendered). EDIT: not true, tried refreshing over and over and the two triangles sometimes show up on very rapid renders (~55ms), sometimes on longer-running ones (~120ms). What does seem to be a recurring pattern is that on the very first time the page is rendered, the two triangles show, and on subsequent repeated refreshes the red one either shows for good or for a very short lapse of time, then flickers away.
Apparently I'm missing something here, let me explain my program's flow in pseudo-code (can include the real code if need be) to see if I'm doing something wrong:
var canvas = new Canvas(/*...*/);
var redTriangle = new Shape(/* vertex positions & colors */);
var blueTriangle = new Shape(/* vertex positions & colors */);
canvas.add(redTriangle, blueTriangle);
canvas.init(); //compiles and links shaders, calls gl.enableVertexAttribArray()
//for vertex attributes "position" and "color"
for(shape in canvas) {
for(bufferType in [PositionBuffer, ColorBuffer]) {
shape.bindBuffer(bufferType); //calls gl.bindBuffer() and gl.bufferData()
//This is equivalent to the initBuffers()
//function in the tutorial
}
}
for(shape in canvas) {
shape.draw();
//calls:
//-gl.bindBuffer() and gl.vertexAttribPointer() for each buffer (position & color),
//-setMatrixUniforms()
//-drawArrays()
//This is equivalent to the drawScene() function in the tutorial
}
Despite the fact I've wrapped the instructions inside object methods in my attempt to make the use of WebGLs slightly more OO, it seems to me I have fully complied to the instructions on this lesson (comparing the lesson's source and my own code), hence I cannot figure out what I'm doing wrong.
I've even tried to use only one for(shape in canvas) loop, as so:
for(shape in canvas) {
for(bufferType in [PositionBuffer, ColorBuffer]) {
shape.bindBuffer(bufferType); //calls gl.bindBuffer() and gl.bufferData()
//This is equivalent to the initBuffers()
//function in the tutorial
}
shape.draw();
//calls:
//-gl.bindBuffer() and gl.vertexAttribPointer() for each buffer (position & color),
//-setMatrixUniforms()
//-drawArrays()
//This is equivalent to the drawScene() function in the tutorial
}
but it doesn't seem to have any effect.
Any clues?
I'm guessing the issue is that by default WebGL canvases are cleared everytime they are composited
Try changing your WebGL context creation to
var gl = someCanvas.getContext("webgl", { preserveDrawingBuffer: true });
I'm just guessing your app is doing things asynchronously which means each triangle is drawn in response to some event? So, if both events happen to come in quick enough (between a single composite) then you get both triangles. If they come on different composites then you'll only see the second one.
preserveDrawingBuffer: true says "don't clear after each composite". Clearing is the default because it allows certain optimizations for certain devices, specifically iOS, and the majority of WebGL apps clear at the beginning of each draw operation. Those few apps that don't clear can set preserveDrawingBuffer: true
In your particular case line 21 of angulargl-canvas.js
options = {alpha: false, premultipliedAlpha: false};
try changing it to
options = {alpha: false, premultipliedAlpha: false, preserveDrawingBuffer: true};

Javascript/Canvas - Create new images from preexisting ones?

I'm wondering if there's a way to take existing images and "stack" them to create a single asset in Javascript.
http://imgur.com/a/ajkBh
The above image album shows what I'd like to do.
Basically, for the game I'm making, I want to procedurally generate enemy NPC's and the like, drawing from a pool of different body parts. Each potential body part would have stats and a spritesheet attached to it, so when the character is randomly generated, I want to stack all of the necessary images together into a single asset that I can then use.
Is there any way to do this?
Canvas is a very basic drawing API with the ability to draw a few basic shapes, strokes and fills. Other than filling with the background color, and/or clearing the whole canvas, there's no way to animate scenes with "sprites" or any complete objects sitting on top of each other, using only the basic canvas API. Copying images in is possible, but then you need to clear them every single frame and replace them, which is a lot of code overhead, if you want them to animate.
You should look into http://createjs.com or a similar "screen graph" type framework, something that sits on top of the canvas and lets you easily load up sprite sheets and move them around. It does the drawing, clearing, rotation, animation etc. of the canvas for you (basically making it a bit like Flash).
In terms of purely stacking or drawing on the canvas, yes you can grab an image and copy it directly onto the canvas using the context2d.drawImage method, but this is probably not going to achieve the effect you want by itself.
You can build up your animation out of existing parts, if think the main issue is organizing the base artworks and having the drawing done to fit one with another.
Let's say :
You want an idle (line 1), walk (line 2), run (line 3)
on each line you have a constant number of frames, say 5.
Say also that your parts are : legs, body, arms, head.
Then you have to build the image by yourself, by stacking those images :
function buildAnimation(legs, body, arms, head) {
var resImg = document.createElement('canvas');
resImg.width = legs.width; resImg.height = legs.height;
var resCtx = resImg.getContext('2d');
resCtx.drawImage(legs,0,0);
resCtx.drawImage(body,0,0);
resCtx.drawImage(arms,0,0);
resCtx.drawImage(head,0,0);
return resImg;
}
then you can feed your game framework with this image, that will be used for an
animation.
The drawback of this method is that you have to draw all animations of all parts
at the same places each time.
Issues :
1) for the head for instance, you might not want to animate it.
2) you might want different height for different characters.
3) it's a lot of work !!
So you might decide of conventions to know where the parts should be drawn, and have
less part to prepare in an image, but a more complex way to build them.
Short example : the file name of the image parts ends with their height, so you can retrieve them
easily. (bodyMonster48.png, bodyHead12.png, ...)
Writing everything would be too much work here, but just a short example :
say we have animWidth, animHeight the size of each anim, and five frames in each
of the 3 anims. Now we just have one head that we want to copy everywhere :
function buildAnimation(animWidth, animHeight, legs, body, arms, head) {
var resImg = document.createElement('canvas');
resImg.width = legs.width; resImg.height = legs.height;
var resCtx = resImg.getContext('2d');
resCtx.drawImage(legs,0,0);
resCtx.drawImage(body,0,0);
resCtx.drawImage(arms,0,0);
// copy the head in all frames of all anims
for (var animLine=0; animLine<3; animLine++) { // iterate in idle, walk, run
for (var animFrame= 0; animFrame<5; animFrame++) { // iterate in images of the animation
resCtx.drawImage(head, animFrame*animWidth, animLine*animHeight);
}
}
return resImg;
}
To be able to build any combination with variable height, you'll
have to carefully parametrize everything, use file naming and positioning conventions,
and you'll surely need a whole helper class not to get lost in all combinations.

D3.js patterns for managing multiple elements bound to same data

I'm learning D3 and my toy application is a visualizer for a 2-dimensional gravity simulation using Symplectic Velocity Verlet Integration.
I have had quite some success animating and drawing a path using bound structured data, but it seems to me that D3 isn't really designed for attaching data to more than one element. It sort of assumes that for any given data that there is a clear and simple SVG element that should own it, and this is evident in the direct storage of data within the __data__ property inside the DOM.
It's not clear, though, the proper way to represent a datum with more than one SVG element. For instance, I'd really prefer to draw a path and a circle for each planet, the path traces its past position (and can have a bunch of clever line-length and color interpolation applied), and the circle plots its current position.
I can even come up with a few more elements I might want to draw: A vector-arrow for velocity... A vector-arrow for acceleration...
In my case, my master data structure is constructed like this, and is dynamically maintained in this structure:
var data = [];
function makeParticle(x, y, vx, vy) {
// state vector plus goodies
return [
x, y,
vx, vy,
0, 0,
[] // path
];
}
data.push(makeParticle(400, 100, -0.5, 1));
data.push(makeParticle(300, -100, 0.5, 2)); // and so on
Each element of data is a planet, which contains its current state vector (position, velocity, and cached acceleration (needed for the integrator)) as well as its path history which is an array of positions which is kept truncated to some reasonably large length.
Currently I am updating the path history like this:
var paths = d3.select('svg').selectAll("path").data(data);
paths.enter().append('path'); // put cool transitions here
paths.exit().remove();
paths.attr("stroke", "red")
.attr("d", function(d){
return lineDrawer(d[6]);
})
This works fine, each path tracks its own copy of its own planet's path.
It's not immediately clear to me how to extend this elegantly to include my circle at the head of each path. I certainly do not want to duplicate the entire datum into the circle's DOM element (as the path data is simply not necessary for it).
Edit in light of my self-answer:
I am hoping that someone can help to elucidate a way to use "groups" to make data-driven the set of things to draw for each datum. e.g. [position, velocity, force, path] as data where they are visualized using, respectively, a circle, an arrow closed path, an arrow closed path, and an open path. It is also possible that this is completely overthinking it because these properties are sort of fixed.
I guess in the process of thinking the problem through, it's become clear to me that all I have to do is filter out the data, so that I only attach the position state data to selectAll('circle.planet') rather than the full datum value which includes the massive path history array. This way it gets exactly the data it is responsible for displaying.
It seems like I have to do some more reading about subselections (I'm mostly puzzled by why (or if) the subselections are limited to two dimensions of hierarchy), but this seems completely reasonable. It seems logical, if I want to draw 4 items for each datum, I just have to somehow "assign" the correct subsets of my datum's structure to each SVG visualizer element.

Sigma JS node animation

I want to move nodes in Sigma JS on click event. Say from position x 0.7 to position x -0.7.
Is it possible to move nodes in Sigma js, and if it is, kindly guide me to achieve that.
Yes, it is possible. I created a jsfiddle showing how to change node position, size, and color on mouse click here:
http://jsfiddle.net/kaliatech/P255K/
You can bind to custom "downnodes" events like this:
sigInst.bind('downnodes',onNodeDown);
The event callback contains an array of selected node ids. I don't know when it would be more than one when clicking. Perhaps when zoomed out in a complex graph.
One of the more subtle issues when using sigmajs, is that most methods, such as getNodes, return clones, not the instances themselves. This is to protect "private" data in the graph I think, especially data that can not be redrawn after initialization. To actually modify properties, you need to use the iterator methods. Even then, you are only given clones. The library updates the actual node instances using a list of predefined allowable properties. (See the checkNode function in graph.js).
After properties have been set, you then need to refresh/redraw the graph. While the "refresh" method would seem to be an obvious candidate, it did not work. I was able to get it to redraw using the draw method though. You will need to review the source code to understand the different parameters. Example:
function onNodeDown(evt) {
var sigmajs = evt.target;
var nodeId = evt.content[0];
sigmajs.iterNodes(function(n){
n.size = 10;
n.color = "#0000FF";
},[nodeId]);
sigmajs.draw(2, 2, 2, true);
};
For more advanced needs, the sigmajs website includes plugin examples showing other ways of getting mouse events and updating nodes dynamically. One is the advanced plugin example for a fisheye effect:
http://sigmajs.org/examples/a_plugin_example_advanced.html
Another is the example for accessing node attributes:
http://sigmajs.org/examples/more_node_info.html
The sigmajs documentation is weak, so you will need to review the source code to understand things.
There are plugins permitting to move isolated nodes from the graph.
Check
https://github.com/Linkurious/linkurious.js/blob/develop/examples/lasso.html

Categories