I am having a jQuery script that loads 15 images and their hover versions (the hover versions are used when... hovering, not when the page loads). In both Chrome and Firefox in the Network tab, i see this :
images/img1.png
images_hover/img1.png
This must mean the hover images are preloaded correctly, but... when i actually hover and those images are used, they are being loaded again. Here is the preload code :
var prel = new Image();
prel.src = "http://hdodov.byethost15.com/color-game/graphics/parts_hover/" + id + ".png";
I tried using the whole path - http://hdodov.byethost15.com/color-game/graphics/parts_hover/ and the short path too (where the root and the script is) - graphics/parts_hover/. It made no difference.
Could this be caused because my images have the same name? They are in different directories though.
For the next question, you really should paste more code, which makes it easier to help you. I checked your URL you provided, but for other people that might have the same problem, it will be hard to understand what went wrong...
OK, as I said, you are always requesting he images again on hover state...
This worked for me:
var context = new Array(15),
canvas = new Array(15),
canvasNum = -1,
hElem,
hElemPrev,
mousePos = {x:-1, y:-1},
images = [], //<-- Store preloaded images here
imagesHover = []; //<-- Store preloaded images here
... then save them on building like this:
function drawMenuItems(id, width, height){
var canNumHolder, createCanvas;
$('#canvas_holder').append($('<canvas></canvas>')
.attr({
width:width,
height:height,
id:id
})
);
canvasNum++;
canvas[canvasNum] = document.getElementById(id);
context[canvasNum] = canvas[canvasNum].getContext('2d');
canNumHolder = canvasNum;
images[id].crossOrigin = 'Anonymous';
images[id].onload = function(){
context[canNumHolder].drawImage(images[id],0,0);
};
images[id].src = 'graphics/parts/' + id + '.png';
//Hover states
imagesHover[id] = new Image();
imagesHover[id].src = "graphics/parts_hover/" + id + ".png";
}
... give just the id...
function hoverStateChange() {
//....rest of the code
if(hElem >= 0){
drawImageOnCanvas(
canvas[hElem],
context[hElem],
"hover", //pass somethink to checke what you want to do
$(canvas[hElem]).attr('id')
);
//....rest of the code
//change to normal texture
if(hElemPrev >= 0){
drawImageOnCanvas(
canvas[hElemPrev],
context[hElemPrev],
"", //pass empty for other state
$(canvas[hElemPrev]).attr('id')
);
$(canvas[hElemPrev]).removeClass('active');
$('#text_holder').removeClass('a' + hElemPrev);
}
.. and finally
function drawImageOnCanvas(canv, contxt, state, src){
contxt.clearRect(0,0,400,400);
if(state == "hover"){
contxt.drawImage(imagesHover[src],0,0);
}else {
contxt.drawImage(images[src],0,0);
}
}
Like this, you chache you images and not calling them again and again...
I hope it helps.
Yuo can preload images with css like this:-
#preload-01 { background: url(http://domain.tld/image-01.png) no-repeat -9999px -9999px; }
Related
I'm having an issue while using canvas in a background page to create data URLs for desktop notifications' images.
I want to use the "image" notifications which require a 3:2 ratio to display properly. The images I want to use (from hulu.com) are a different ratio, so I decided to use the canvas element to create the corresponding data URL off of these images so that the ratio is correct. It kind of works in theory, but…
…I'm having issues if I'm creating more than one canvas/notification in the background page. One image is created properly, but the rest comes out empty.
Confusingly, opening the same background page in a new tab (i.e. exact same code) makes everything works just fine: all the notifications are created with the images loaded from hulu.com. Also, just changing the dimensions from 360x240 to 300x200 makes it work. Finally, though they're similar computers with the same Chrome version (34.0.1847.116), it works without modification at work while it doesn't on my own laptop.
I made a test extension available at the bottom of this post. Basically, it only has a generated background page. The code for that page is this:
var images = ["http://ib2.huluim.com/video/60376901?size=290x160&img=1",
"http://ib2.huluim.com/video/60366793?size=290x160&img=1",
"http://ib4.huluim.com/video/60372951?size=290x160&img=1",
"http://ib1.huluim.com/video/60365336?size=290x160&img=1",
"http://ib3.huluim.com/video/60376290?size=290x160&img=1",
"http://ib4.huluim.com/video/60377231?size=290x160&img=1",
"http://ib4.huluim.com/video/60312203?size=290x160&img=1",
"http://ib1.huluim.com/video/60376972?size=290x160&img=1",
"http://ib4.huluim.com/video/60376971?size=290x160&img=1",
"http://ib1.huluim.com/video/60376616?size=290x160&img=1"];
for (var i = 0; i < 10; i++) {
getDataURL(i);
}
/*
* Gets the data URL for an image URL
*/
function getDataURL(i) {
var img = new Image();
img.onload = function() {
var canvas = document.createElement('canvas');
canvas.width = 360;
canvas.height = 240;
var ctx = canvas.getContext('2d');
ctx.drawImage(this, 0, 0);
ctx.fillStyle = "rgb(200,0,0)";
ctx.fillRect (10, 10, 55, 50);
var dataURL = canvas.toDataURL('image/png');
chrome.notifications.create('', {
type: 'image',
iconUrl: 'logo_128x128.png',
title: String(i),
message: 'message',
imageUrl: dataURL
}, function(id) {});
}
//img.src = chrome.extension.getURL('logo_128x128.png');;
img.src = images[i];
}
The commented out line for img.src = ... is a test where it loads a local file instead of a remote one. In that case, all the images are created.
The red rectangle added to the canvas is to show that it's not just the remote image that is an issue: the whole resulting canvas is empty, without any red rectangle.
If you download and add the test extension below, you should get 10 notifications but only one with an image.
Then, to open the background page in a new tab, you can inspect the background page, type this in the console:
chrome.extension.getURL('_generated_background_page.html')
and right-click the URL, and click "Open in a new Tab" (or window). Once open you should get 10 notifications that look fine.
Any idea of what is going on? I haven't been able to find any kind of limitations for background pages relevant to that. Any help would be appreciated, because this has been driving me crazy!
Files available here: https://www.dropbox.com/s/ejbh6wq0qixb7a8/canvastest.zip
edit: based on #GameAlchemist's comment, I also tried the following: same getDataURL method, but the loop wrapped inside an onload for the logo:
function loop() {
for (var i = 0; i < 10; i++) {
getDataURL(i);
}
}
var logo = new Image();
logo.onload = function () {
loop();
}
logo.src = chrome.extension.getURL('logo_128x128.png');
Remember that the create() method is asynchronous and you should use a callback with. The callback can invoke next image fetching.
I would suggest doing this in two steps:
Load all the images first
Process the image queue
The reason is that you can utilize the asynchronous image loading better this way instead of chaining the callbacks which would force you to load one and one image.
For example:
Image loader
var urls = ["http://ib2.huluim.com/video/60376901?size=290x160&img=1",
"http://ib2.huluim.com/video/60366793?size=290x160&img=1",
"http://ib4.huluim.com/video/60372951?size=290x160&img=1",
"http://ib1.huluim.com/video/60365336?size=290x160&img=1",
"http://ib3.huluim.com/video/60376290?size=290x160&img=1",
"http://ib4.huluim.com/video/60377231?size=290x160&img=1",
"http://ib4.huluim.com/video/60312203?size=290x160&img=1",
"http://ib1.huluim.com/video/60376972?size=290x160&img=1",
"http://ib4.huluim.com/video/60376971?size=290x160&img=1",
"http://ib1.huluim.com/video/60376616?size=290x160&img=1"];
var images = [], // store image objects
count = urls.length; // for loader
for (var i = 0; i < urls.length; i++) {
var img = new Image; // create image
img.onload = loader; // share loader handler
img.src = urls[i]; // start loading
images.push(img); // push image object in array
}
function loader() {
count--;
if (count === 0) process(); // all loaded, start processing
}
//TODO need error handling here as well
Fiddle with concept code for loader
Processing
Now the processing can be isolated from the loading:
function process() {
// share a single canvas (use clearRect() later if needed)
var canvas = document.createElement('canvas'),
ctx = canvas.getContext('2d'),
current = 0;
canvas.width = 360;
canvas.height = 240;
createImage(); // invoke processing for first image
function createImage() {
ctx.drawImage(images[current], 0, 0); // draw current image
ctx.fillStyle = "rgb(200,0,0)";
ctx.fillRect (10, 10, 55, 50);
chrome.notifications.create('', {
type : 'image',
iconUrl : 'logo_128x128.png',
title : String(i),
message : 'message',
imageUrl: canvas.toDataURL() // png is default
},
function(id) { // use callback
current++; // next in queue
if (current < images.length) {
createImage(); // call again if more images
}
else {
done(); // we're done -> continue to done()
}
});
}
}
Disclaimer: I don't have a test environment to test Chrome extensions so typos/errors may be present.
Hope this helps!
I've got multiple images, and I'd like to load them each into a single <canvas> element at different points in time and then manipulate them using CamanJS. I can get the first image to appear like this:
Caman('#canvas-element', '/images/one.jpg');
But then when I subsequently try to update that same element using the following code, it does not work.
Caman('#canvas-element', '/images/two.jpg');
Is there some way to reset/clear/flush the canvas and load new image data into it, or do I really need to create separate <canvas> elements for each image I want to load? I'd prefer a single element because I don't want to eat up all the memory.
Remove the Caman attribute (data-caman-id) from the IMG or CANVAS element, change the image, and then re-render Caman.
document
.querySelector('#view_image')
.removeAttribute('data-caman-id');
const switch_img = '/to/dir/img.png';
Caman("#view_image", switch_img, function() {
this.render();
});
Hope followed code can help others who have same require.
function loadImage(source) {
var canvas = document.getElementById('image_id');
var context = canvas.getContext('2d');
var image = new Image();
image.onload = function() {
context.drawImage(image, 0, 0, 960, 600);
};
image.src = source;
}
function change_image(source) {
loadImage(source);
Caman('#image_id', source, function () {
this.reloadCanvasData();
this.exposure(-10);
this.brightness(5);
this.render();
});
}
Just figured this one out with a lot of trial and error and then a duh moment!
Instead of creating my canvas directly in my html, I created a container and then just did the following:
var retStr = "<canvas id=\"" + myName + "Canvas\"></canvas>";
document.getElementById('photoFilterCanvasContainer').innerHTML = retStr;
Caman("#" + myName + "Canvas", myUrl, function() {
this.render();
});
You want the canvas id to be unique each time you access the Caman function with a new image.
I want to load 4 images from background showing a load bar to the client
and when the images will be downloaded i want to set them as background images to 4 div blocks.
I am looking for something like this.
var myImages = new Array();
for(var i = 0; i < 4; i++)
myImages[i] = new Image();
//load images using the src attribute
//and execute an on load event function where to do something like this.
var div0 = document.getElementById('theDivId');
div0.style.backgroundImage = myImage[index];
Is there any way to set a background image using an Image javascript object?
You can do something close to what you had. You don't set an image background to be an image object, but you can get the .src attribute from the image object and apply that to the backgroundImage. Once the image object has successfully loaded, the image will be cached by the browser so when you set the .src on any other object, the image will load quickly. You could use this type of code:
var imgSrcs = [...]; // array of URLs
var myImages = [], img;
for (var i = 0; i < 4; i++) {
img = new Image();
img.onload = function() {
// decide which object on the page to load this image into
// this part of the code is missing because you haven't explained how you
// want it to work
var div0 = document.getElementById('theDivId');
div0.style.backgroundImage = "url(" + this.src + ")";
};
img.src = imgSrcs[i];
myImages[i] = img;
}
The missing part of this code is deciding which objects on the page to load which image into when the image loads successfully as your example stood, you were just loading each one into the same page object as soon as they all loaded which probably isn't what you want. As I don't really know what you wanted and you didn't specify, I can't fill in that part of the code.
One thing to watch out for when using the .onload event with images is you have to set your .onload handler before you set the .src attribute. If you don't, you may miss the .onload event if the image is already cached (and thus it loads immediately).
This way, the image shows up instantly all in one once it's loaded rather than line by line.
function setBackgroundImage(){
imageIsLoaded(myURL).then(function(value) {
doc.querySelector("body > main").style.backgroundImage = "url(" + myURL + ")";
}
}
function imageIsLoaded(url){
return new Promise(function(resolve, reject){
var img = new Image();
try {
img.addEventListener('load', function() {
resolve (true);
}, false);
img.addEventListener('error', function() {
resolve (false);
}, false);
}
catch(error) {
resolve (false);
}
img.src = url;
});
}
My user can upload really big images, and for cropping and display purposes i'm adding width attribute so it will fit well in the browser window. Real image size can be - say 1920 x 1080 px.
<!-- width added for display purpose -->
<img class="croppable" src="images/fhd.jpg" width="640" />
In order to calculate real selection box dimension (if the x coordinate is 20px then would be 60px in the original full hd picture) i need to get the full image size before apply the width attribute.
The problem is that this will return 640 as value, taking into account the width attribute:
// Important: Use load event to avoid problems with webkit browser like safari
// when using cached images
$(window).load(function(){
$('img.croppable').each(function(){
alert(this.width);
});
});
Please don't flag this as duplicate since what i'm asking is completly different from simple image width/height retrival (which works, actually).
EDIT: Chris G. solution seems not working:
$(window).load(function(){
$('img.croppable').each(function(){
console.log(this.src);
var original = new Image(this.src);
console.log(original);
$("#original_w").text(original.width); // Temp, more images to be added
$("#original_h").text(original.height); // Temp, more images to be added
});
});
Console output:
http://localhost/DigitLifeAdminExtension/images/pillars-of-creation.jpg
<img width="0">
Get the width/height of the image itself, not the div it is contained within.
$(window).load(function(){
$('img.croppable').each(function(){
var img = new Image();
img.src = $(this).src;
alert(img.width);
});
});
You can remove the attributes, get the width and put the attributes in place again:
var $img = $(img);
var oldWidth = $img.attr("width");
var imgWidth = $img.removeAttr("width").width();
$img.width(oldWidth);
But I think Chris G.'s answer works well too, just making sure it will be loaded when you try to get the width:
img.onload = function() {
if (!img.complete) return; // IMG not loaded
width = img.width;
imgManipulationGoesHere();
}
Works in most up-to-date browsers and IE9.
$(window).load(function(){
$('img.croppable').each(function(){
alert(this.naturalHeight);
});
});
The working solution would be:
$(function(){
$('img.croppable').each(function () {
var original = new Image(this.src);
original.onload = function () {
alert(original.src + ': ' + original.width + 'x' +original.height);
};
});
});
I've read about various kinds of ways getting image dimensions once an image has fully loaded, but would it be possible to get the dimensions of any image once it just started to load?
I haven't found much about this by searching (which makes me believe it's not possible), but the fact that a browser (in my case Firefox) shows the dimensions of any image I open up in a new tab right in the title after it just started loading the image gives me hope that there actually is a way and I just missed the right keywords to find it.
You are right that one can get image dimensions before it's fully loaded.
Here's a solution (demo):
var img = document.createElement('img');
img.src = 'some-image.jpg';
var poll = setInterval(function () {
if (img.naturalWidth) {
clearInterval(poll);
console.log(img.naturalWidth, img.naturalHeight);
}
}, 10);
img.onload = function () { console.log('Fully loaded'); }
The following code returns width/height as soon as it's available. For testing change abc123 in image source to any random string to prevent caching.
There is a JSFiddle Demo as well.
<div id="info"></div>
<img id="image" src="https://upload.wikimedia.org/wikipedia/commons/d/da/Island_Archway,_Great_Ocean_Rd,_Victoria,_Australia_-_Nov_08.jpg?abc123">
<script>
getImageSize($('#image'), function(width, height) {
$('#info').text(width + ',' + height);
});
function getImageSize(img, callback) {
var $img = $(img);
var wait = setInterval(function() {
var w = $img[0].naturalWidth,
h = $img[0].naturalHeight;
if (w && h) {
clearInterval(wait);
callback.apply(this, [w, h]);
}
}, 30);
}
</script>
One way is to use the HEAD request, which asks for HTTP Header of the response only. I know in HEAD responses, the size of the body is included. But I don't know if there anything available for size of images.