Code:
var getImageFromUrl = function(url, callback) {
var img = new Image();
img.onError = function() {
alert('Cannot load image: "'+url+'"');
};
img.onload = function() {
callback(img);
};
img.src = url;
}
getImageFromUrl(somurl, Nextline);
LINE1-//should come here after callback(img)
I wanted that after img.onload function the compiler will run code in line1
Actually you can do this using JQuery Callback function.
var getImageFromUrl = function(url, callback) {
var img = new Image();
img.onError = function() {
alert('Cannot load image: "'+url+'"');
};
img.onload = function() {
callback(img);
};
img.src = url;
}
var callBack = $.Callbacks();
callBack.add(getImageFromUrl(somurl, Nextline));
callBack.add(function(){
// LINE 1 logic can be executed here.
});
callBack.fire();
For further reference, please refer to here
Related
I have a situation where I need to wait for a img.onload function to resize a picture.
The img.onload function is located within a synchronious function, which can not be async.
I need to wait for the img.onload before I can continue inside the synchronious function.
Does anyone have an idea on how to realize it?
Example:
function test(img) {
const img = new Image();
img.onload = function () {
//Here needs something to happen, set a variable
x = value;
};
//After the img.onload I need to access this here
console.log(x);
}
This is what I have so far.
I know that img.onload will be executed later and console.log(x) is fired before that, but it needs to be afterwards. I can sadly not just move it into img.onload because this function test is used to upload and wont work otherwise.
Appreciating any tips.
EDIT:
Actual code I am using to resize an image before uploading.
Uploading takes place in the test function, after this code:
img.onload = function () {
URL.revokeObjectURL(this.src);
const [newWidth, newHeight] = calculateSize(img, MAX_WIDTH, MAX_HEIGHT);
const canvas = document.createElement("canvas");
canvas.width = newWidth;
canvas.height = newHeight;
const ctx = canvas.getContext("2d");
ctx.drawImage(img, 0, 0, newWidth, newHeight);
canvas.style = "display: none";
canvas.toBlob(
(blob) => {
// Handle the compressed image. es. upload or save in local state
let file_small = new File([blob], name,{type:"image/jpeg", lastModified:new Date().getTime()});
let container = new DataTransfer();
container.items.add(file_small);
ajaxData.set('upload', container.files[0]);
console.log("END of the onload");
},
MIME_TYPE,
QUALITY
);
};
Below is the example, but you can update as you want.
async function test() {
const myImage = new Image(100, 200);
myImage.src = 'https://images.kiwi.com/airlines/128x128/0B.png';
document.body.appendChild(myImage);
await callFunction(myImage);
console.log('called second');
}
function callFunction(img) {
return new Promise((resolve, reject) => {
img.onload = () => {
//here you all code goes
console.log('called first');
resolve(true)
}
})
}
test()
please vote answer as a useful if this is a solution, thank you in advance.
I have a vue app. I use this.data to access it's data variables and methods.
In a certain method I have to use img.onload to get the width of an image. But there are 2 "this" now and vue js methods and variables are not working now. I need an alternative solution so both will work.
vueMethod(url) {
var img = new Image();
img.onload = function() {
this.size = {this.width,this.height} //size is a vue variable
}
img.src = url;
}
You could assign this to a variable called vm before calling img.onload function as follows
vueMethod(url) {
var img = new Image();
let vm = this;
img.onload = function() {
vm.size = { this.width, this.height } //size is a vue variable
}
img.src = url;
}
You can use an arrow function (documentation) to keep the englobing scope:
vueMethod(url) {
var img = new Image();
img.onload = () => {
this.size = {img.width, img.height}
}
img.src = url;
}
In this example, this will have the same reference as if you used it next to var img
You should save Vue instance into a variable outside the img.onload scope
try with:
vueMethod(url) {
var img = new Image();
var vm = this;
img.onload = function() {
vm.size = {this.width,this.height} //size is a vue variable
}
img.src = url;
}
Put var that = this; inside your img funciton.
That will give you scope in your function, or bind your function when you call it e.g
vueMethod("url").bind(this)
So when you use a function with the keyword function it creates a new scope for this to refer to consider the below example
const obj = {
size: 10,
testFunc() {
console.log(this, 'now obj')
const func = function () {
// this now refers to function its currently in
}
const otherFunc = () => console.log(this, 'refers to obj still')
},
testFunc2: () => {
console.log(this, 'now window')
}
}
any questions let me know and i'll be happy to help
const obj = {
size: 10,
vueMethod(url) {
console.log(this.size, 'this now refers to obj')
const img = new Image();
const self = this;
img.onload = function() {
console.log(this, 'this now refers to img')
console.log(self.size, 'but you can reassign this to a var outside the scope');
self.size = {
width: this.width,
height: this.height
}
};
// mocking the onload dont include this
img.onload();
img.src = url;
}
}
obj.vueMethod()
i have this function to create new images to load them in memory
function preloadImgs() {
var imgDomain = "http://imgs.domain/";
if (document.images) {
var img1 = new Image();
var img2 = new Image();
var img3 = new Image();
img1.src = imgDomain + "images/1/cover.jpg";
img2.src = imgDomain + "images/2/cover.jpg";
img3.src = imgDomain + "images/3/cover.jpg";
} }
// initialize the function
preloadImgs()
i need a way to know when all images in preloadImgs() function have been loaded , how can i achive that using the same code that i have provided ?
You can use a promise pattern.
https://developers.google.com/web/fundamentals/getting-started/primers/promises
Although these aren't natively supported everywhere, jQuery (tagged) provides an implementation:
https://api.jquery.com/promise/
Combined with img.onload to resolve the promises you can respond to an array of promises by:
var arrayOfPromises = [];
var $deferred = $.Deferred();
var img = new Image();
img.onload = function() {
// Check your support needs # http://caniuse.com/#search=naturalWidth
if (img.naturalWidth && img.naturalHeight) {
$deferred.resolve()
} else {
$deferred.reject();
}
};
img.onerror = $deferred.reject;
img.src = 'someimage.png';
arrayOfPromises.push($deferred);
$.when.apply($, arrayOfPromises).then(function() {
// your callback, images all loaded
alert('OK')
}, function() {
// Any failed image load occur
alert('FAIL')
});
I'm trying to get my head around why this doesn't work and wondered if someone could help me out. Basically I need multiple instances of this object with different images and I need each object to store the image height/width for its associated image for further operations, however the onload event never fires?
Sorry guys to be clear heres the complete code, if you see the TestTheVar function imgW is never set to anything.
<script type="text/javascript">
(function() {
var myTest = new TestObj();
mytest.TestTheVar();
})();
function TestObj() {
this.img = new Image();
this.img.onload = function(){
this.imgW = this.img.width;
this.imgH = this.img.height;
};
this.img.src = "reel_normal.PNG";
this.TestTheVar = function() {
alert(this.imgW);
}
}
</script>
You have two problems here
1) scope
2) timing
Scope, as mentioned in other answers refers to the fact that this inside the onload function is the Image object and not your TestObj so you would need to do the following:
<script type="text/javascript">
(function() {
var myTest = new TestObj();
mytest.TestTheVar();
})();
function TestObj() {
var self = this;
this.img = new Image();
this.img.onload = function(){
self.imgW = this.width;
self.imgH = this.height;
};
this.img.src = "reel_normal.PNG";
this.TestTheVar = function() {
alert(this.imgW);
}
}
</script>
Timing refers to the fact that you cannot assume the image has finished loading by the time you are trying to access height and width. This is what callbacks are good for:
<script type="text/javascript">
(function() {
var myTest = new TestObj(function() {
myTest.TestTheVar();
});
})();
function TestObj(cb) {
cb = cb || function() {};
var self = this;
this.img = new Image();
this.img.onload = function(){
self.imgW = this.width;
self.imgH = this.height;
cb();
};
this.img.src = "reel_normal.PNG";
this.TestTheVar = function() {
alert(this.imgW);
}
}
</script>
this is a keyword that belongs to each function.
In the load event listener it will be the image, not your TestObj instance.
Therefore, you can
Use this.img.imgW to get it:
function TestObj() {
var that = this;
this.img = new Image();
this.img.onload = function(){
this.imgW = this.width;
this.imgH = this.height;
that.testTheVar();
};
this.img.src = "reel_normal.PNG";
this.testTheVar = function() {
alert(this.img.imgW);
};
}
Store it in your TestObj instance:
function TestObj() {
var that = this;
this.img = new Image();
this.img.onload = function(){
that.imgW = this.width;
that.imgH = this.height;
that.testTheVar();
};
this.img.src = "reel_normal.PNG";
this.testTheVar = function() {
alert(this.imgW);
};
}
Customize this inside the event handler to be your TestObj instance:
function TestObj() {
this.img = new Image();
this.img.onload = (function(){
this.imgW = this.img.width;
this.imgH = this.img.height;
this.testTheVar();
}).bind(this);
this.img.src = "reel_normal.PNG";
this.testTheVar = function() {
alert(this.imgW);
};
}
I need to be able to wait to start a function until the height and width of an image are available. When this code calls start(), it still says the height and width are zero:
var img = new Image();
init = function() {
img.onload = this.start();
img.src = "sky.jpg";
}
start = function() {
alert("Start called.\nwidth:"+img.width+"\nheight"+img.height);
}
init();
How can I make it wait until the dimensions are available before calling start()?
var img = new Image();
var start = function() {
alert("Start called.\nwidth:"+img.width+"\nheight"+img.height);
}
var init = function() {
img.onload = start;
img.src = "sky.jpg";
}
init();
Change this.start() to start.
I also scoped your functions.