I am making a multiple choice quiz game for canvas, where users upload their own images for multiple choice answers.
When the next question is selected, the variables for the next question are got from a javascript array, including filepath for the image.
The problem I am having with this is that usually on the first quiz attempt, images sometimes do not load in time to be drawn on the canvas. I am trying to improve the performance of the canvas side of the quiz, by ensuring image answers are always drawn.
Help would be greatly appreciated. The code for drawing images on canvas is below.
//else if answer type is image answer
else if(answertype == "image"){
answerbg.src = "./resources/imageaudiovideoanswerbg.png";
eventstate = 'imageaget';
if (answerbg.complete) {
context.drawImage(answerbg, 0, 280);
context.drawImage(imagefilea,75,285);
context.drawImage(imagefileb,375,285);
context.drawImage(imagefilec,75,591);
context.drawImage(imagefiled,375,591);
}
else {
answerbg.onload = function () {
context.drawImage(answerbg, 0, 280);
context.drawImage(imagefilea,75,285);
context.drawImage(imagefileb,375,285);
context.drawImage(imagefilec,75,591);
context.drawImage(imagefiled,375,591);
};
}
}
You have to make sure that the image is loaded before you can draw it on canvas.
So what you would have to do is somthing like:
var image = new Image(); //make a new image object
image.onload = function() { //when the image has loaded...
doStuffWithImage(); //Do somthing with it (draw it on canvas etc.)
}
image.src = '/your/path/image.png'; //set the source (afterwards!)
This is something you have to know if your working with images and canvas.
Also if you have trouble loading all the images make a preLoadAllImagesfromSource(sourceArray) function, where all the images objects are allready preloaded when the main code is executed.
Hope that helped.
Alternatively you can consider embedding the image and/or other resources using BASE64 encoding in the JavaScript or the HTML itself.
http://ejohn.org/blog/embedding-and-encoding-in-javascript/
Of course in your case since it is a user uploaded content, you may have to generate the JavaScript from the uploaded image.
Related
I'm trying to develop a JavaScript application for modulating house plans with jsketcher. You can view project here. For modulating plans, I need to load the plan on the canvas, then try to modulate with the tools present in the jsketcher2D. I've manged to load the plan but couldn't find a way to keep it below the other elements of the canvas. I need the elements which are drawn with jsketcher2D to be on top of the plan image. Could you please help me with this?
Thank you very much
modifications made to static/sketcher.bundle.js
Line 49532
function addPlan(){
let canvas = document.getElementById('viewer');
let plan = canvas.getContext("2d")
let base_image = new Image();
base_image.src = 'img/back.png';
plan.drawImage(base_image, 0, 0);
}
Line 47461
addPlan();
You need to show more code. The most likely reason this is happening is you have your addPlan() function running after you draw on the canvas. The first things drawn will be on the back of the canvas and the last things drawn will be above.
addPlan(); // Background
canvasContext.fillRect(0, 0, 50, 50); // will be on top of image
I'm two days into js,html and css programming. So very newbie!
Following and building upon this TUTORIAL
Q1: How can I add this male into the background (see figuere 1.) and prohibit any strokes outside of the borders?
Adding image to background was no biggy!
function make_base()
{
base_image = new Image();
base_image.src = 'img/bmapFront.gif';
base_image.onload = function(){
context.drawImage(base_image, 0,0);
}
}
There is a context.clip function, not sure if I can use pixel form as clipping path. Making tons of "image substractions" isn't the best way.
Any suggestions
Edit:
Did the Job for me: VeryHelpful
var frontPath = new Path2D ("M 133.41,17.00 C 141.37,2.41 160.66, !VERY LONG! ")
context.clip(frontPath);
Messy strokes!
He should look like this. Then I want to save him.
Although there is such a thing as ctx.clip(), this is sometimes not what's wanted as it's impractical to use a path.
The solution that I like involves creating a virtual empty canvas onto which you draw your pixel image. Through various manipulations, like using ctx.getImageData and similar to make sure you only get one kind of color or apply other filters only once, you can obtain an image that seems to be empty (alpha of 0, mostly) in the places where you want to clip other images or paths out.
At that point, you'd use ctx.globalCompositeOperation = 'source-atop', or pick another one you might want to use from mdn's list of globalCompositeOperations.
At this point, you can just draw this virtual canvas image onto the main canvas
I am using fabric Js on canvas where:
I am developing a product page for an e-commerce website where
I have drawn a background image and created a polygon on it and then inside of the polygon I have uploaded images, that works fine.
But now I have to make an image crop function inside the polygon for each image so that when I click on it I can crop it.
I have used canvas context.drawImage();. Function which works fine but when I click on the image or anywhere else on the canvas it disappears and I can't select it.
Can any one please help me with it ?
The code follows as
var image = new Image();
image.src = "uploads/cat.jpg";
image.onload = function(){
context.drawImage(image, 0, 19, 69, 97, 300, 100, 103, 145);
context.Image.selectable = true;
}
I could be missing something here without seeing more context but I think if you used fabric.Image feature to draw your image instead of context.draw image it might work? Seems like there might be an issue happening with mixing fabric functions and regular canvas drawing. image.Fabric
Sorry if I misunderstood! I'm a little fuzzy on the description of your image/shape stack order, screenshot might help if this answer doesn't apply.
I have been unsuccessfully trying to find documentation that details the limitations regarding the Html5 Canvas Element such as what is the largest image file size it can load etc. The reason I ask is that I have been trying to resize image sizes ranging from 50kb to 2.0mb through ctx.scale(), yet it has been horribly inconsistent in that for the same image sometimes ctx.drawImage() will be successful and other times unsuccessful (unsuccessful being no re-scaled image appears in the canvas).
I have also placed console.log(base64) to monitor the result of var base64 = canvas.toDataURL() and have noticed that when successfully resized the resized base64 will be quite a long string as expected and when unsuccessfully resized a string will still appear yet be relatively short and outputs a blank image.
Does this have something to do with memory limitations and the unsuccessful strings wrapping around themselves? If so, what are the memory limitations imposed on the canvas element?
First:
Hard limitations would depend on the browser, not the canvas API.
Even then, browsers are always trying to improve that performance, so that number would always be changing.
But with WebGL and Canvas being used to make games, texture atlases / sprite atlases are HUGE .jpg/.png files.
Chances are very, very good that your images are smaller, and I've frequently used 4MB/5MB/16MB images in canvas for demonstrations.
A huge image (or dozens of them) might crash the tab, if it's big enough, but until that time, canvas hasn't really complained to me.
Second:
There are security-limitations.
Editing photos in canvas comes down to what browser you're on, and whether the file is on the same domain as your website or not.
Third:
When you say that "large files don't work, but they do sometimes..."
...that leads me to believe that your image-loading method is faulty.
If you do something like this:
var canvas = document.createElement("canvas"),
context = canvas.getContext("2d"),
img = new Image();
img.src = "//mydomain.com/myimg.png";
context.drawImage(img, 0, 0, img.width, img.height);
...or anything else which isn't either event-based or callback-based,
then your problem has nothing to do with canvas and has everything to do with callbacks, and that you're trying to draw the image to the canvas before the image is done loading.
If your browser has already cached a copy of the large image, or if a small image only takes a fraction of a second to download, then there's no problem.
If you try downloading an 18MB image, and draw it to the canvas as soon as you set the url for the image, then you're going to get a blank screen, because it hasn't finished loading.
Instead, you need to wait for the image to finish loading, and then draw it to the canvas when it's ready.
var canvas = document.createElement("canvas"),
context = canvas.getContext("2d"),
image = new Image();
image.onload = function () {
var img = this,
width = img.width,
height = img.height;
canvas.width = width;
canvas.height = height;
context.drawImage(img, 0, 0, width, height);
document.body.appendChild(canvas);
};
image.src = "//mydomain.com/path-to-really-huge-image.png";
Now it could be a 16MP image. Nothing will happen until the file is done loading.
Then, the onload event fires, and does the rest of the setup.
You could make it more abstract, and turn it into a nifty program, but it feels like this is the key piece you might be missing.
I am faced with a problem that slows down animation on a canvas, as various pictures move left, right, up and down. I need advice on how to optimize the animation.
It is important that the animation works on all main browsers, in particular: Chrome, Firefox and Internet Explorer.
Is it possible to optimize the animation? Maybe put a delay on the drawing? Thank you in advance.
In javascript you can use the setInterval and setTimeout functions to create delays and throttle the frame rate.
for instance if you wanted to make your drawing loop approximately 30 FPS you could have some code that looks like this:
function draw(){
var canvas = document.getElementById('myCanvas');
//create the image object
var img = new Image();
//set the image object's image file path
var img.src = "images/myImage.png"
//check to see that our canvas exists
if( canvas.getContext )
{
//grab the context to draw to.
var ctx = cvs.getContext('2d');
//clear the screen to a white background first
//NOTE to make this faster you can clear just the parts
//of the canvas that are moving instead of the whole thing
//every time. Check out 'Improving HTML5 Canvas Performance'
//link mention in other post
ctx.fillStyle="rgb(255,255,255)";
ctx.fillRect (0, 0,512, 512);
//DO ALL YOUR DRAWING HERE....
//draw animation
ctx.drawImage(img, 0, 0);
}
//Recalls this draw update 30 times per second
setTimeout(draw,1000/30);
}
This will help you control how much processing time the animation is taking. Thus if you find that your animation is going too slow you can increase the frame rate by changing the denominator '30' to something like '60' fps or anything that really works well for your program.
As far as optimizing goes in addition to setTimeout() the way you draw your animations is critical too. Try to load all your images before you render them this is called "Preloading". That is if you have a bunch of different images for each animated cell then before you call your draw function load all the images into an array of images like so:
var loadedImages = new Array();
loadedImages[0] = new Image();
loadedImages[0].src = "images/animationFrame1.png";
loadedImages[1] = new Image();
loadedImages[1].src = "images/animationFrame2.png";
loadedImages[2] = new Image();
loadedImages[2].src = "images/animationFrame3.png";
loadedImages[3] = new Image();
loadedImages[3].src = "images/animationFrame4.png";
you could even put them in a hash if it makes sense for you app where instead of
loadedImages[0] = new Image();
loadedImages[0].src = "images/animationFrame1.png";
you do this
loadedImages['frame1'] = new Image();
loadedImages['frame1'].src = "images/animationFrame1.png";
once you have all your images loaded you references them for drawing by doing calling them like so:
//Using the integer array
ctx.drawImage(loadedImages[0], 0, 0);
//OR
//Using the stringed hash
ctx.drawImage(loadedImages['frame1'], 0, 0);
You want to separate your loading process from your rendering process because loading images is process intensive thus will slow your animations down if you are loading things while rendering.
That is not to say that you can't ever load anything while rendering, but instead just be conscience that this will slow animation speed down.
Here is an article on preloading images.
There is another post on here which talks about consistent animation speed on all browsers here
Note the link posted by the green checked answer
Other things to be noted are making sure to only clearing and redrawing bounding boxes as mentioned in the post with HTML 5 canvas optimization. That link has some really good techniques to be conscience of while developing canvas animations.
Here are some frame works as well which might come in handy to cross compare what you are doing to what other engines are doing.
Hope some of this helps. I am new to javascript (only started coding with it about 2 weeks ago) and so there could be better ways to do things but these are the things I have found thus far.
window.requestAnimationFrame() is one sure way to make your animation run smoother.
https://developer.mozilla.org/en/DOM/window.mozRequestAnimationFrame
(cross browser http://paulirish.com/2011/requestanimationframe-for-smart-animating/ )
However it doesn't fix the possible problems with your drawing code which was missing from the question.