What is wrong with this function?
window.LoadImage = function(el, canvasId){
var canvas = document.getElementById(canvasId);
var context = canvas.getContext("2d");
var dialogCanvas = document.getElementsByClassName('dialogCanvas');
var dialogContext = dialogCanvas[0].getContext("2d");
var reader = new FileReader();
reader.onload = function(event){
var img = new Image();
img.onload = function(){
var w = 545;
var imgW = img.width;
var imgH = img.height;
var dialogW = dialogCanvas[0].width;
var dialogH = dialogCanvas[0].height;
h = (imgH / imgW) * w;
dialogH = (imgH / imgW) * dialogW;
context.clearRect(0, 0, w, imgH);
dialogContext.clearRect(0,0, dialogW, 250);
canvas.width = w;
canvas. height = h;
context.drawImage(img,0,0,w,h);
dialogContext.drawImage(img,0,0,dialogW, dialogH);
}
img.src = event.target.result;
}
reader.readAsDataURL(event.target.files[0]);
}
I am trying to draw 2 different canvas with this function. Neither work on Firefox. And the damn thing works on Chrome and IE.
The "dialogCanvas" is a preview which is inside a jquery modal box and the other, reached using the "canvasId" parameter, has it's display = "none", in the page.
I'm not getting any errors on firefox. Actually, I can't even debug it.
Thanks in advance.
Edit
jsfiddle = http://jsfiddle.net/cgEv8/
This line:
reader.readAsDataURL(event.target.files[0]);
refers to "event". Where's that? In some browsers it's a global object, but not in Firefox.
As already pointed out the event is undefined. In Firefox I get this error on the fiddle:
ReferenceError: event is not defined. Try to handle event
You should rather handle the event using:
$('#t1-1-img-header').on('change', LoadImage);
Then in you handler you can use
function LoadImage(event) {
var el = this; /// this will be the calling element
...
}
(and of course you need to remove the onchange attribute in the element itself).
For the canvas ID you need to either pass it in directly or use some other means to store it so it is available to the callback scope.
Modified fiddle here
Related
This question already has an answer here:
context.filter not working on safari
(1 answer)
Closed 1 year ago.
I am trying to add a filter to my image that is uploaded from my computer, but no filters are applied. I write ctx.filter = "contrast(1.6)" to apply filters, but it doesn't work. Everything else works perfectly.
I think it might be a compatibility issue. However, I am not quite sure. I use Safari as my browser. If it is a problem with Safari is it any way I can make it work with Safari?
Here is the code:
var imageLoader = document.getElementById('imageLoader');
imageLoader.addEventListener('change', handleImage, false);
var canvas = document.getElementById('imageCanvas');
var ctx = canvas.getContext('2d');
var img;
function handleImage(e){
var reader = new FileReader();
reader.onload = function(event){
img = new Image();
img.onload = function(){
var ratio = this.height / this.width;
canvas.height = canvas.width * ratio;
ctx.filter = "contrast(1.6)"
ctx.drawImage(img,0,0,canvas.width, canvas.height);
}
img.src = event.target.result;
}
reader.readAsDataURL(e.target.files[0]);
}
ctx.filter does not work in safari
you can use this library for work in safari
https://github.com/davidenke/context-filter-polyfill
or
http://ocanvas.org/
ctx.filter does not support in safari
Link: https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/filter
So I am trying to create an image element and then draw it onto a canvas with Javascript for an assingment. Here is my code
function drawCanvas() {
document.getElementById("heading").innerHTML = "Canvas Information";
document.getElementById("output").innerHTML = "";
clearCanvas();
var x = document.createElement("IMG");
x.setAttribute("src", "pudge.png");
var c = document.getElementById("myCanvas");
ctx = c.getContext('2d');
c.width = window.innerWidth;
c.height = window.innerHeight;
ctx.drawImage(x,0,0);
My problem is that for some reason, the code won't work on the first try, but after I run it once it will work fine, even if clear the canvas my other functions. I assume it can't create an image and then draw it on the canvas in one go, because if I put the image element straight into html with some id and call it like I did the canvas with getElementById then it works, but I wanted to create the element in the function itself without modifying the HTML. I tried creating a createImage() function with just
var x = document.createElement("IMG");
x.setAttribute("src", "pudge.png");
return x;
to no avail. Any help?
Edit: Sorry for the lack of code, this was an assignment so I didn't want to put out too much code that someone could find and copy. I was about to post it but someone answered already below with the eventlistener tip, TY guys!
You need to allow the image to load first. Once it loads, you can draw it to the canvas.
Add addEventListener('load', e => ...) to your image
function drawCanvas() {
document.getElementById("heading").innerHTML = "Canvas Information";
document.getElementById("output").innerHTML = "";
clearCanvas();
var x = document.createElement("IMG");
x.setAttribute("src", "pudge.png");
x.addEventListener('load', e => {
var c = document.getElementById("myCanvas");
ctx = c.getContext('2d');
c.width = window.innerWidth;
c.height = window.innerHeight;
ctx.drawImage(x, 0, 0);
})
}
Side note: Not sure if there is a difference, but you can use var x = new Image instead of document.createElement('img')
I nearly have the theory down but am getting stuck wit the fine details. An image sizing function, given a var $data (which is the event object of a file input after changing) will return a var dataurl back (which is a dataurl jpeg).
My issue was getting dataurl to recognise it was updated inside a nested function. The code, as I show it below, was logging data:image/jpg;base64 to the console, showing dataurl was not updated.
Research led me to find that this is due to the asynchronous calls and this makes sense. The var wasn't changed in time before moving on and printing to the console. I've also learned that this is a standard situation to issue a callback to update the var.
Having made a few attempts at doing so, I can't find a clean (or working) method to update the var using a callback. I'll expand on this after I show my current code:
function clProcessImages($data) {
var filesToUpload = $data.target.files;
var file = filesToUpload[0];
var canvas = document.createElement('canvas');
var dataurl = 'data:image/jpg;base64';
var img = document.createElement("img");
var reader = new FileReader();
reader.onload = function(e, callback) {
img.onload = function () {
var ctx = canvas.getContext("2d");
ctx.drawImage(img, 0, 0);
var MAX_WIDTH = 800;
var MAX_HEIGHT = 600;
var width = img.width;
var height = img.height;
if (width > height) {
if (width > MAX_WIDTH) {
height *= MAX_WIDTH / width;
width = MAX_WIDTH;
}
} else {
if (height > MAX_HEIGHT) {
width *= MAX_HEIGHT / height;
height = MAX_HEIGHT;
}
}
canvas.width = width;
canvas.height = height;
var ctx = canvas.getContext("2d");
ctx.drawImage(img, 0, 0, width, height);
dataurl = canvas.toDataURL("image/jpeg",0.8);
callback(dataurl);
}
img.src = e.target.result
}
reader.readAsDataURL(file);
console.log(dataurl); // console log mentioned in question
return dataurl;
};
This is the code as it stands, somewhere in the middle of figuring out how to pull off the callback. I'm aware that in its shown state the callback isn't called.
My first hurdle was that I (seemingly) couldn't later call the reader.onload function again, as it appears to be an event specifically to be fired when the object is loaded, not something to call on manually at any time. My best guess was to create a new function that reader.onload would trigger, would contain all of the the current reader.onload function and I could specify directly later, to issue the callback, skipping referring to the onload event.
Seemed like a sound theory, but then I got stuck with the event object that the onload function passes through. Suppose I apply the above theory and the onload event calls the new function readerOnLoad(e). It would pass through the event object fine. However, when wanting to perform a callback later, how could I manually call readerOnLoad(e) as I don't see a way to pass on the event object from the same FileReader in an elegant way. It feels a little like I'm straying into very messy code* to solve whereas it feels like there should be something a little bit more elegant for a situation that doesn't feel too niche.
*The original $data event object variable was obtained by storing a global variable when a file input detected a change. In theory, I could create a global variable to store the event object for the FileReader onload. It just feels quite convoluted, in that the difference between my original code and a code that functions this way is quite severe and inelegant when the only difference is updating a var that wasn't ready in time.
When working with asynchronous function, you would usually want to pass a function as callback. You can use NodeJS style callback like this:
// asyncTask is an asynchronous function that takes 3 arguments, the last one being a callback
asyncTask(arg1, arg2, function(err, result) {
if (err) return handleError(err);
handleResult(result);
})
So in your case, you can do:
clProcessImages($data, function(dataurl) {
console.log(dataurl);
// Do you other thing here
});
function clProcessImages($data, onProcessedCallback) {
var filesToUpload = $data.target.files;
var file = filesToUpload[0];
var canvas = document.createElement('canvas');
var dataurl = 'data:image/jpg;base64';
var img = document.createElement("img");
var reader = new FileReader();
reader.onload = function(e) {
img.onload = function () {
var ctx = canvas.getContext("2d");
ctx.drawImage(img, 0, 0);
var MAX_WIDTH = 800;
var MAX_HEIGHT = 600;
var width = img.width;
var height = img.height;
if (width > height) {
if (width > MAX_WIDTH) {
height *= MAX_WIDTH / width;
width = MAX_WIDTH;
}
} else {
if (height > MAX_HEIGHT) {
width *= MAX_HEIGHT / height;
height = MAX_HEIGHT;
}
}
canvas.width = width;
canvas.height = height;
var ctx = canvas.getContext("2d");
ctx.drawImage(img, 0, 0, width, height);
dataurl = canvas.toDataURL("image/jpeg",0.8);
onProcessedCallback(dataurl);
}
img.src = e.target.result
}
reader.readAsDataURL(file);
return dataurl;
};
You might also want to pass error object to the callback like the first example, and handle it appropriately.
In short, always add a callback function as an argument to your own asynchronous function.
I have been trying to get an image drawn on the canvas however have failed to do so. The HTML code simply creates the canvas element "canvas1" with no additional processing.
Here is the JS:
function loadlogo(){
var logo = new Image();
var canvas = document.getElementById('canvas1');
var context = canvas.getContext('2d');
//resize the canvas to the current window
context.canvas.width = window.innerWidth;
context.canvas.height = window.innerHeight / 3;
logo.src = "images/1.png";
logo.onload = function() {context.drawImage(logo,0,0;};
context.shadowOffsetX = 50;
context.shadowOffsetY = 30;
context.shadowColor = "pink";
}
window.addEventListener("load",loadlogo,false);
window.addEventListener("resize",loadlogo,false);
Any help you could give would be awesome!!!
I have tried this many ways and am stuck.
Thanks,
Bryan
Put your onload function for img before you assign img src
Change this part
{context.drawImage(logo,0,0;};
^ Notice the missing end-parenthesis here
to
{context.drawImage(logo,0,0)};
I would as QBM5 also recommend to put the src after setting onload to be sure it's properly initialized.
I'm experimenting with the canvas element, but for some reason it doesn't display my image.
I use the following code:
function Canvas() {
this.field = function() {
var battlefield = document.getElementById('battlefield');
var canvas = battlefield.getElementsByTagName('canvas')[0];
return canvas.getContext('2d');
}
}
function Draw(canvas) {
if (!canvas) {
alert('There is no canvas available (yet)!');
return false;
}
this.canvas = canvas;
this.grass = function(pos_x, pos_y) {
var terrain = new Terrain();
var specs = terrain.grass();
var img = new Image();
img.onload = function(){
canvas.drawImage(img, specs.position_x, specs.position_y, specs.dimension_x, specs.dimension_y, pos_x, pos_y, specs.dimension_x, specs.dimension_y);
console.log('success???'); // this is being output
};
img.src = '/img/terrain.png';
}
}
(function() {
var canvas = new Canvas();
var draw = new Draw(canvas.field());
draw.grass();
})();
There are no errors, but the image just doesn't display. I've verified if the image exists and it does. I also verified the specs and they do contain what they should:
dimension_x: 25
dimension_y: 25
position_x: 0
position_y: 0
Any idea what I'm doing wrong?
http://jsfiddle.net/uwkfD/3/
pos_x and pos_y are undefined in your code. It works if you pass values for them to draw.grass():
draw.grass(0, 0);
DEMO
Tested in Chrome and Firefox.
This may be because you need a context to draw on.
Try:
this.context = canvas.getContext('2d')
Then call your draw functions on the context object not the canvas object:
this.context.drawImage(img, specs.position_x, specs.position_y, specs.dimension_x, specs.dimension_y, pos_x, pos_y, specs.dimension_x, specs.dimension_y);
It also appears that your reference to canvas is wrong too, it should be this.canvas (or this.context) not just canvas, at least as I understand scope in javascript.