I tried to build many konvajs canvas and transform them to konva images.
And finally load these images to another canvas and show.
function main(){
var total_konva_stage= createStage();
var imagesLayer= new Konva.Layer();
for (var key in array){
$(".tmpcontainer").remove();
containerName = containerNameBase + key;
$("#hidden_div").append("<div id='"+containerName+"' class='tmpcontainer'></div>");
var konva_stage =createcanvas(containerName); //create a hidden dynamic div and bind this stage to it
var img = konva_stage .toDataURL("image/png");
var imageObj = new Image();
imageObj.src = img
imageObj.onload = function() {
callback_canvastoImg(imagesLayer, imageObj);
};
}
total_konva_stage.add(imagesLayer);
total_konva_stage.show();
total_konva_stage.draw();
}
function callback_canvastoImg(imagesLayer, imageObj){
var konva_image = new Konva.Image({imageObj});
imagesLayer.add(konva_image );
}
What I think my results is that "total_konva_stage" will have every separate img that from konva_stage.
But I found my second img will contain the first img , my third img contain the first, second img
I have no idea now, please help.
Thanks
onload function callback is asynchronous. It means it will be executed only after the whole array is processed.
So in this line: callback_canvastoImg(imagesLayer, imageObj); variable imageObj will refer to the LAST created image.
To avoid this you can:
Use modern js syntax of declaring variables (in case you should use something like babel)
const imageObj = new Image();
You can define closure function for loop iteration. You just need to use array.forEach instead of for loop:
array.forEach(function(item, key) {
$(".tmpcontainer").remove();
containerName = containerNameBase + key;
$("#hidden_div").append("<div id='"+containerName+"' class='tmpcontainer'></div>");
var konva_stage =createcanvas(containerName); //create a hidden dynamic div and bind this stage to it
var img = konva_stage .toDataURL("image/png");
var imageObj = new Image();
imageObj.src = img
imageObj.onload = function() {
callback_canvastoImg(imagesLayer, imageObj);
};
}
Related
*Update with link to question I reference If I load multiple images with the for loop, do I only need one img.onload function?
I want to bring in many image files to use in canvas via an array of all the images (that way they load before I need them), Using a solution found on here I'm getting the error
"Uncaught TypeError: Cannot read property 'drawImage' of undefined
at Image. (app.js:32)" line 32 would be canvasContext[value].drawImage(images[i], 0, 0);
Obviously, I didn't understand the solution because I'm kind of at a loss as to what is causing this.
The end result would be for me to set up all the images on load and then in the draw function I have, declare their positions and sizing.
window.onload = function() {
console.log(keysDown);
canvas = document.getElementById('myCanvas');
canvasContext = canvas.getContext('2d');
var images = ['Frylock.png', 'Master_Shake.png'];
// Assign onload handler to each image in array
for (var i = 0; i <= images.length; i++) {
var img = new Image();
img.onload = (function(value) {
return function() {
canvasContext[value].drawImage(images[i], 0, 0);
}
})(i);
// IMPORTANT - Assign src last for IE
img.src = './' + images[i];
}
I'm using OpenLayers to draw a map, and I'd like to fill the polygon that describes a country with a photo from that country. I know I can pass a CanvasPattern to ol.style.Fill's color, but I don't know to generate an image.
Here's my code, and a JSfiddle with a full example: http://jsfiddle.net/07366L44/5/
function getPhoto() {
var canvas = document.createElement('canvas');
var context = canvas.getContext('2d');
var photo = new Image();
photo.src = 'http://i.imgur.com/C6PL9tB.jpg';
return context.createPattern(photo, 'repeat');
}
I think it's because the photo is loaded async. Other examples create the pattern in the photo.onload method but I don't know how to return that.
Optimally I'd like to return a canvas which I can animate or update later with other photos, but I'll settle for just a single static image per country!
You'll have to set your style's fill color in the image's onload handler.
/**
* #param {ol.style.Style} style Style to set the pattern on.
*/
function setPattern(style) {
var canvas = document.createElement('canvas');
var context = canvas.getContext('2d');
var photo = new Image();
photo.onload = function() {
canvas.width = photo.width;
canvas.height = photo.height;
var pattern = context.createPattern(photo, 'repeat');
style.getFill().setColor(pattern);
}
photo.src = 'http://i.imgur.com/C6PL9tB.jpg';
}
Note that the fill's color needs to be set before the style function is called, so you cannot call the setPattern function in the style function. It's better to create the style before loading the layer.
I would like to use the drawImage() function to load an image in a Javascript animation, but the image does not load with my current code. I think I need to specifically ask for the image to be loaded at some point, but I'm not sure when or how. The idea is to make a cloud that goes across the canvas. Thank you for your help.
function draw(x,y){
var canvas = document.getElementById('canvas');
var ctx = canvas.getContext('2d');
x += 2;
if(x>1000){
x=0;
}
var cloud = new image();
cloud.src='small_cloud.png';
ctx.drawImage(cloud,x,0);
var loopTimer = setTimeout('draw('+x+','+y+')',20);
}
Try new Image()rather than new image()
Also move
var canvas = document.getElementById('canvas');
var ctx = canvas.getContext('2d');
var cloud = new image();
cloud.src='small_cloud.png';
to outside the draw()function, as you only want to set these things up once. Delay this setting up until the browser has had time to parse the document, for example using
window.onload = function(){ ... };
(Though in reality you'd have to make sure not to overwrite any existing window.onload listeners by using proper even handler registration.) Also delay the first invocation to draw()until the image has loaded, for example like so:
cloud.onload = function(){
draw(cloud, 0, 0);
}
I'd also change
var loopTimer = setTimeout('draw('+x+','+y+')',20);
to
setTimeout(function(){ draw(x, y); }, 20);
since you seem not to be using the loopTimer variable, and since passing setTimeout an anonymous function rather than a string is considered better practice.
Finally, it would look like this:
window.onload = function() {
var canvas = document.getElementById('canvas');
var ctx = canvas.getContext('2d');
var cloud = new image();
cloud.src='small_cloud.png';
cloud.onload = function(){
draw(ctx, cloud, 0, 0);
};
};
function draw(ctx, cloud, x,y){
x += 2;
if(x>1000){
x=0;
}
ctx.drawImage(cloud,x,0);
setTimeout(function(){ draw(ctx, cloud, x, y); }, 20);
}
Note that, since ctx is no longer defined inside the draw() function, as it is local to the anonymous window.onload function, you also has to pass ctx to the draw() function.
function LoadResources(){
alert("In load socket");
var canvas = document.getElementById("myCanvas");
var context = canvas.getContext("2d");
var tiles= new Array();
var loadedCount=0;
for (x = 101; x <= 155; x++) {
var imageObj = new Image(); // new instance for each image
imageObj.src = "Resources/ClassicCardImages/deck1/dood_deck/"+x+".GIF";
imageObj.onload=function(){
loadedCount++;
if(loadedCount==55){
cardsImagesLoaded();
}else {
alert(loadedCount);
}
};
tiles.push(imageObj);
}
};
So when i call the function LoadResources() it does give the alert "in load socket" but does not gives the alert while in imageObj.onload function.
You can use window.onload function i.e "window.onload = function() {..}" and my function in it while use in the body of html document.
Plus i m running it on Google chrome .Is there the problem with chrome's onload or something .
You are trying to increase the loading counter even if the onload function are called only once (at the moment when the images has been loaded completely), so there is no way to trigger the alert many times. For me it's not quite obvious what are you trying to do. Anyway if you want to load multiple images with onload function the best practice is to use a closure, otherwise on each iteration it may happens that at the end of the loop you will get only the last image loaded. I'm not going into detail into what a closure is, but the principle is something like this:
for (var i = 0; i< 4; i++) {
var imgObj = new Image();
imgObj.onload = (function(img) {
return function () {
ctx.drawImage(imgObj, 0, 0);
}
})(i);
imgObj.src = 'image.png';
}
This way by calling a new function you will create a new execution context retaining the value of i on each iteration.
I am just adding a little help for your code.
For assigning functions the way you're doing it , it is cheaper to do it the way below.
for (x = 101; x <= 155; x++) {
var imageObj = new Image(); // new instance for each image
imageObj.src = "Resources/ClassicCardImages/deck1/dood_deck/"+x+".GIF";
imageObj.onload= imageOnLoad;
}
function imageOnLoad(){
loadedCount++;
if(loadedCount==55){
cardsImagesLoaded();
}else {
alert(loadedCount);
}
};
tiles.push(imageObj);
}
I am lost in this error. I am trying to write a function and write a array in that function. in an external js file. This is going to be a random image loading function but i keep getting an error with the array and can't figure out why.
function randImg(){
var imgs = new Array();
img[0]="banner1.png";
img[1]="banner2.png";
img[2]="banner3.png";
var maxium = img.length;
}
I am getting the error on the var imgs line. any ideas?
Here is my new code calling the variable "img" was throwing me off it loads ok but it only prints out the text in the variable and not the actually file!? so at run it say "banner1.png" or "banner3.png"? any thoughts
function randImg(){
var banner = new Array();
banner[0] = "banner1.png";
banner[1] = "banner2.png";
banner[2] = "banner3.png";
var maxImg = banner.length;
var randNum = Math.floor(Math.random()*maxImg);
return banner[randNum];
}
A better way to define the array with its elements:
var img = [
"banner1.png",
"banner2.png",
"banner3.png",
"banner4.png"
]
And this is the function you might need:
function randImg(){
var img = [
"banner1.png",
"banner2.png",
"banner3.png",
"banner4.png"
]
var maxImg = img.length;
var randNum = Math.floor(Math.random()*maxImg)
return img[randNum]
}
Your variable names should be consistent. You created the new Array imgs (local variable), yet you added to img (defaulted to global variable, since you didn't declare it a local variable).
Also, note that in Javascript it doesn't make too much sense to add a var statement that is not the first line of a function. This is because of hoisting. Essentially, Javascript will take your var and move it to the first line, setting the variable to undefine. This may or may not affect how your program works vs how you think it should work, so it's best to add all your vars at the top of your functions. Javascript has function scope, not block scope.
(also note that maximum is a more meaningful variable name than maxium)
// This adds to the newly created array:
function randImg(){
var img = new Array(), // Note: img NOT imgs
maximum; // Even if a var is below this line, Javascript hoists it here
img[0] = "banner1.png";
img[1] = "banner2.png";
img[2] = "banner3.png";
maximum = img.length;
}
and you can use .push() if you're just adding to the end of an array (like you're doing)
function randImg(){
var img = new Array(), // Note: img NOT imgs
maximum;
img.push("banner1.png");
img.push("banner2.png");
img.push("banner3.png");
maximum = img.length;
}
or
function randImg(){
var img = new Array(), // Note: img NOT imgs
maximum;
img.push("banner1.png").push("banner2.png").push("banner3.png)";
maximum = img.length;
}
or better yet, just use [] to initialize an empty array or [a,b,c,...] to initialize an array with elements. Also, why use var twice?
function randImg(){
var img = ["banner1.png","banner2.png","banner3.png"], // note comma
maximum = img.length;
}
Finally, to live up to the name of the function
var randImg = function() {
var img = ["banner1.png","banner2.png","banner3.png"];
return img[Math.floor(Math.random()*img.length)];
}
... and here's a working example of randImg()