i have a problem with canvas.
i can draw a canvas with single image, but i can't draw each canvas with image separate.
- if data just have one image it's working fine, but data have multiple image it's not working
can you help me ?
<script>
var h_notepad = 500;
var w_notepad = 737;
var data = [
{dataImageURL: "1_sat_1.png"},
{dataImageURL: "1_sat_2.png"},
{dataImageURL: "1_sat_3.png"},
{dataImageURL: "1_sat_4.png"}
];
for(var i = 0; i < data.length ; i++){
var canvas = document.createElement('canvas');
var ctx = canvas.getContext('2d');
var img = new Image();
canvas.width = w_notepad;
canvas.height = h_notepad;
img.crossOrigin = 'anonymous';
img.width = w_notepad;
img.height = h_notepad;
console.log(img);
img.onload = function(){
ctx.drawImage(img, 0, 0, w_notepad, h_notepad);
};
img.src = data[i].dataImageURL;
$('body').append(canvas);
}
</script>
<html>
<head>
<meta charset="utf-8">
<title>DRAWING</title>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.3/jquery.min.js"></script>
<meta charset="utf-8">
</head>
<body>
</body>
</html>
I guess you only get the last one.
It's a closure problem.
When the load event fires, img and ctx only refer to the last ones created.
So you draw data.length time on the same canvas.
To avoid it, you can use this and wrap the canvas creation in the onload handler:
var imgs = ['http://lorempixel.com/200/300/', 'http://lorempixel.com/500/300/', 'http://lorempixel.com/200/100/'];
for (var i = 0; i < imgs.length; i++) {
var img = new Image();
var width = 500;
var height = 300;
img.onload = function() {
var c = document.createElement('canvas');
c.width = width;
c.height = height;
document.body.appendChild(c);
var ctx = c.getContext('2d');
ctx.drawImage(this, 0,0, width, height);
};
img.src = imgs[i];
}
Problem is that onload is asynchronous. So all your code runs before any of onload functions will be called. That is why your function
img.onload = function(){
ctx.drawImage(img, 0, 0, w_notepad, h_notepad);
};
uses the latest ctx and renders all images in this context.
What you can do is cover this asynchronous call with a synchronous function scope:
(function(ctx, img, w_notepad, h_notepad) {
img.onload = function(){
ctx.drawImage(img, 0, 0, w_notepad, h_notepad);
};
})(ctx, img, w_notepad, h_notepad);
This isolates the variables and keeps there values until you receive the image.
Related
I am trying to take a pattern and apply it over a png image but only cover the non-transparent part of the image similar to this one.
http://jsfiddle.net/eLmmA/1/
$(function() {
var canvas = document.createElement('canvas');
canvas.width = 250;
canvas.height = 250;
var canvas_context = canvas.getContext("2d");
var img = new Image();
img.onload = function(){
var msk = new Image();
msk.onload = function(){
canvas_context.drawImage(img, 0, 0);
canvas_context.globalCompositeOperation = "destination-in";
canvas_context.drawImage(msk, 0, 0);
canvas_context.globalCompositeOperation = "source-over";
};
msk.src = 'http://i.stack.imgur.com/QtQrZ.png';
}
img.src = 'http://i.stack.imgur.com/MDGFY.jpg';
document.body.appendChild(canvas);
});
The example above is really close to what I want but I need to be able to use a smaller texture image and repeat it over the none pattern image. I am not familiar with how to use canvas properly but trying to learn more about it.
Thanks in advance!
Never mind I figured it out.
var canvas = document.createElement('canvas');
canvas.width = 250;
canvas.height = 250;
var canvas_context = canvas.getContext("2d");
var img = new Image();
img.onload = function(){
var msk = new Image();
msk.onload = function(){
var ptrn = canvas_context.createPattern(img, 'repeat');
canvas_context.fillStyle = ptrn;
canvas_context.fillRect(0, 0, canvas.width, canvas.height);
canvas_context.drawImage(img, 0, 0);
canvas_context.globalCompositeOperation = "destination-in";
canvas_context.drawImage(msk, 0, 0);
canvas_context.globalCompositeOperation = "source-over";
};
msk.src = $('#base_url').data('base')+'assets/themes/img/download.png';
}
img.src = $('#base_url').data('base')+'assets/uploads/thumbs/1381413411Purple-Night-Owls-thumb.jpg';
$('#itemPreview').html(canvas);
I have done lots of research, and i'v become completely stumped on this issue.
The code is supposed to resize the dataURL to 500x500px. However, it ends up with a blank image.
The original dataURL variable at the top of the code IS valid. I console.log it, and it works when opening it in the browser. So I don't think that's the issue.
$('#img-resizer .do-it').bindFirst("click", function () {
originalImg = $("#img-resizer img.original").cropper('getCroppedCanvas').toDataURL('image/jpeg');
var img = document.createElement("img");
img.src = originalImg;
var canvas = document.createElement("canvas");
canvas.width = 500;
canvas.height = 500;
var ctx = canvas.getContext("2d");
ctx.width = 500;
ctx.height = 500;
ctx.drawImage(img, 0, 0, 500, 500);
cropImg = canvas.toDataURL("image/png");
$($("#img-resizer").attr("save-to")).attr("src", cropImg);
});
So what ends up happening, is the cropImg variable is just a blank image when opened in my browser.
As I said earlier, I am positive that the originalImg variable is valid, as I console.log it and it works when opened.
Thanks.
add load event. very important
remove unnecessary ctx.width/height
$('#img-resizer .do-it').bindFirst("click", function() {
originalImg = $("#img-resizer img.original").cropper('getCroppedCanvas').toDataURL('image/jpeg');
var img = document.createElement("img");
img.onload = function() {
var canvas = document.createElement("canvas");
canvas.width = 500;
canvas.height = 500;
var ctx = canvas.getContext("2d");
ctx.drawImage(img, 0, 0, 500, 500);
var cropImg = canvas.toDataURL("image/png");
$($("#img-resizer").attr("save-to")).attr("src", cropImg);
}
img.src = originalImg;
});
I am using this code to display data of two canvas into third canvas but it is not working.
I am saving the two canvas data using localstorage and passing it to third canvas
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
//First canvas data
var img1 = loadImage(localStorage.getItem('cbdata'), main);
//Second canvas data
var img2 = loadImage(localStorage.getItem('cbdata1'), main);
var imagesLoaded = 0;
function main() {
imagesLoaded += 1;
if (imagesLoaded == 2) {
// composite now
ctx.drawImage(img1, 0, 0);
ctx.globalAlpha = 0.5;
ctx.drawImage(img2, 0, 0);
}
}
function loadImage(src, onload) {
var img = new Image();
img.onload = onload;
img.src = src;
return img;
}
Your code works. Check that the content of localStorage.getItem is non-empty. And I also slightly modified display of the images by changing ctx.drawImage commands:
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
//First canvas data
var img1 = loadImage('http://ep01.epimg.net/elpais/imagenes/2015/10/21/ciencia/1445444934_907402_1445781076_portada_normal.jpg', main);
//Second canvas data
var img2 = loadImage('http://ep01.epimg.net/economia/imagenes/2015/10/22/actualidad/1445508003_507635_1445508894_portada_normal.jpg', main);
var imagesLoaded = 0;
function main() {
imagesLoaded += 1;
if (imagesLoaded == 2) {
// composite now
ctx.drawImage(img1, 0, 0, 100, 100);
ctx.globalAlpha = 0.5;
ctx.drawImage(img2, 100, 0, 100, 100);
}
}
function loadImage(src, onload) {
console.log('loadImage', src);
var img = new Image();
img.onload = onload;
img.src = src;
return img;
}
https://jsfiddle.net/4Le4g8ta/
As far as I can see my code is exactly like the code on W3schools except im making a new image instead of using one already in the html, but i cant get it to display anything
<body>
<center><canvas id="myCanvas" width="1000" height="750"></canvas></center>
<script>
function newImage(src, width, height) {
var img = document.createElement("img");
img.src = src;
img.width = width;
img.height = height;
return img;
}
var c = document.getElementById("myCanvas");
var ctx = c.getContext("2d");
var i = newImage("http://i.imgur.com/ELsS4mN.jpg", 1000, 750);
ctx.drawImage(i,0,0);
</script>
The problem appears because you return image object before it is fully downloaded. Because of that canvas fails to render image data as background image.
You should make use of onload callback function and drawImage only when image data is completely available. This should work:
function newImage(src, width, height, callback) {
var img = new Image();
img.width = width;
img.height = height;
img.onload = function () {
callback(img);
};
img.src = src;
}
var c = document.getElementById("myCanvas"),
ctx = c.getContext("2d");
newImage("http://i.imgur.com/ELsS4mN.jpg", 1000, 750, function(image) {
ctx.drawImage(image, 0, 0);
});
Note how instead of returning image from newImage function, you pass callback function in it and invoke it once download complete.
function newImage(src, width, height, callback) {
var img = new Image();
img.width = width;
img.height = height;
img.onload = function () {
callback(img);
};
img.src = src;
}
var c = document.getElementById("myCanvas"),
ctx = c.getContext("2d");
newImage("http://i.imgur.com/ELsS4mN.jpg", 1000, 750, function(image) {
ctx.drawImage(image, 0, 0);
});
<canvas id="myCanvas" width="1000" height="750"></canvas>
I have a canvas with an id called napkin. When I call the following function it is supposed to draw an image and the napkin canvas onto another canvas in memory. It works on every browser but IOS Safari. The operation does not seem to exceed the IOS memory cap for the canvas. I test this by calling k().toDataURL(). Any ideas?
function k() {
var canvas = document.createElement('canvas');
var napkin = document.getElementById("napkin");
var img = new Image();
img.src = picurl;
var ctx = canvas.getContext("2d");
var imgdata = new Image();
imgdata.src = napkin.toDataURL();
canvas.width = img.width;
canvas.height = img.height;
ctx.drawImage(img, 0, 0);
ctx.globalAlpha = 0.5;
ctx.drawImage(imgdata, 0, 0);
return canvas;
}
You need to wait for the image data to load before using it...
var img = new Image();
img.onload = function(){
// do stuff here with img
};
img.src = picurl;
// not here