I am draw background on canvas and also small images on that background. But sometimes, background draw on small images. Why ?
JavaScript code -
var canvasupdate = document.getElementById("myCanvas");
ctxupdate = canvasupdate.getContext("2d");
var background = new Image();
background.src = sitePath + "ATOM/chapter1/book/" + `bgimagename`;
background.onload = function() {
ctxupdate.drawImage(background, 0, 0); // set background image
};
var imageobj = new Array();
for (var d = 0; d < calloutImageArray.length; d++) // getting small images in array
{
imageobj[d] = new Image();
(function(d) {
imageobj[d].src = sitePath + "ATOM/chapter1/book/" + calloutImageArray[d];
imageobj[d].onload = function() {
ctxupdate.drawImage(imageobj[d], calloutImageArrayX[d], calloutImageArrayY[d], calloutImageArrayW[d], calloutImageArrayH[d]);
};
})(d);
}
In above code, background image code should be execute first then call out image(small image) code execute but some time execute small images code and then background image code why?
All the images are loaded asynchronously. So sometimes the small images are loaded (and drawn) before the background image. Please take a look into e.g. Network tab in Chrome in which order the resources load is done.
The simplest solution for this problem is to move the loading of small images into the callback function for load event of the background image.
The onLoad function runs asynchronously. That means JavaScript will continue to run the rest of your code and will run the callback function when the background image is loaded. That's why your second part of the code runs first. So instead try to add your code inside the onload function like this:
var canvasupdate = document.getElementById("myCanvas");
ctxupdate = canvasupdate.getContext("2d");
var background = new Image();
background.src = sitePath + "ATOM/chapter1/book/" + `bgimagename`;
background.onload = function() {
ctxupdate.drawImage(background, 0, 0); // set background image
var imageobj = new Array();
for (var d = 0; d < calloutImageArray.length; d++) // getting small images in array
{
imageobj[d] = new Image();
(function(d) {
imageobj[d].src = sitePath + "ATOM/chapter1/book/" + calloutImageArray[d];
imageobj[d].onload = function() {
ctxupdate.drawImage(imageobj[d], calloutImageArrayX[d], calloutImageArrayY[d], calloutImageArrayW[d], calloutImageArrayH[d]);
};
})(d);
}
};
that way you can be sure that the background will be set first and then your small images. Note that I didn't try your code to check if it does what you want, I just rearranged the code blocks to show you the logic and why does not run as you would expect.
Hope it helps
Related
Please answer this question, as I am struggling a lot with it.
I am trying to change image source on mouse over. I am able to do it, but image is not displaying on page.
I am trying to change image source to cross domain URL. I can see that in DOM image source is changing but on page its not.
I have tried all solutions mentioned in LINK, but none of them is working.
Please let me solution to problem.
NOTE:
I can see in network tab image is taking some time to download (about 1 sec).
It is an intermediate issue, sometime image is loading and sometimes its not
CODE:
document.getElementsByTagName('img')[0].addEventListener('mouseover', function()
{
document.getElementsByTagName('img')[0].setAttribute('src', 'url/of/the/image');
});
have you tried loading images before everything else?
function initImages(){
var imC = 0;
var imN = 0;
for ( var i in Images ) imN++;
for(var i in Images){
var t=Images[i];
Images[i]=new Image();
Images[i].src=t;
Images[i].onload = function (){
imC++;
if(imC == imN){
console.log("Load Completed");
preloaded = 1;
}
}
}
}
and
var Images = {
one image: "path/to/1.png",
....
}
then
if( preloaded == 1 ){
start_your_page();
}
Here the code that will remove the img tag and replace it with a new one:
document.getElementsByTagName('img')[0].addEventListener('mouseover', function() {
var parent = document.getElementsByTagName('img')[0].parentElement;
parent.removeChild(document.getElementsByTagName('img')[0]);
var new_img = document.createElement("img");
new_img.src = "https://upload.wikimedia.org/wikipedia/commons/6/69/600x400_kastra.jpg";
parent.appendChild(new_img);
});
<img src="https://www.w3schools.com/w3images/fjords.jpg">
I resolved the issue using code:
function displayImage() {
let image = new image();
image.src="source/of/image/returned/from/service";
image.addEventListener('load', function () {
document.getElementsByTagName('img')[0].src = image.src;
},false);
}
Here in code, I am attaching load event to image, source of image will be changed after image is loaded.
I am working with a single canvas that allows the user to click on a window pane in a window image. The idea is to show where the user has clicked. The image will then be modified (by drawing a grill on the window) and then saved to in JPEG. I am saving the canvas image prior to the click function because I don't want the selection box to show in the final image. However, Firefox often displays a blank canvas when restoring the canvas where IE and Chrome do not. This works perfectly in Chrome and IE. Any suggestions? Does Firefox have a problem with toDataURL()? Maybe some async issue going on here? I am also aware that saving a canvas in this fashion is memory intensive and there may be a better way to do this but I'm working with what I have.
Code:
/**
* Restores canvas from drawingView.canvasRestorePoint if there are any restores saved
*/
restoreCanvas:function()
{
var inverseScale = (1/drawingView.scaleFactor);
var canvas = document.getElementById("drawPop.canvasOne");
var c = canvas.getContext("2d");
if (drawingView.canvasRestorePoint[0]!=null)
{
c.clearRect(0,0,canvas.width,canvas.height);
var img = new Image();
img.src = drawingView.canvasRestorePoint.pop();
c.scale(inverseScale,inverseScale);
c.drawImage(img, 0, 0);
c.scale(drawingView.scaleFactor, drawingView.scaleFactor);
}
},
/**
* Pushes canvas into drawingView.canvasRestorePoint
*/
saveCanvas:function()
{
var canvas = document.getElementById("drawPop.canvasOne");
var urlData = canvas.toDataURL();
drawingView.canvasRestorePoint.push(urlData);
},
EXAMPLE OF USE:
readGrillInputs:function()
{
var glassNum = ir.get("drawPop.grillGlassNum").value;
var panelNum = ir.get("drawPop.grillPanelNum").value;
drawingView.restoreCanvas();
drawEngine.drawGrill(glassNum, panelNum,null);
drawingView.saveCanvas();
},
sortClick:function(event)
{
..... //Sorts where user has clicked and generates panel/glass num
.....
drawingView.showClick(panelNum, glassNum);
},
showClick:function(panelNum, glassNum)
{
var glass = item.panels[panelNum].glasses[glassNum];
var c = drawEngine.context;
drawingView.restoreCanvas();
drawingView.saveCanvas();
c.strokeStyle = "red";
c.strokeRect(glass.x, glass.y, glass.w, glass.h);
},
By just looking at the code setting the img.src is an async action to retrieve the image, so when you try to draw it 2 lines later to the canvas, it probably hasn't been loaded yet (having it in cache will make it return fast enough that it might work).
You should instead use an img.onload function to draw the image when it has loaded.
restoreCanvas:function()
{
var inverseScale = (1/drawingView.scaleFactor);
var canvas = document.getElementById("drawPop.canvasOne");
var c = canvas.getContext("2d");
if (drawingView.canvasRestorePoint[0]!=null)
{
c.clearRect(0,0,canvas.width,canvas.height);
var img = new Image();
img.onload = function() {
c.scale(inverseScale,inverseScale);
c.drawImage(img, 0, 0);
c.scale(drawingView.scaleFactor, drawingView.scaleFactor);
};
img.src = drawingView.canvasRestorePoint.pop();
}
},
I have a masonry grid where the images are black and white and when you hover over them, the color images appear. They are not composite images. They are all separate. (I'm just sorting out bugs for someone else's code)
On initial hover after a fresh page load, there is a delay (and grey overlay) when hovering over. After the initial, it's of course instantaneous when it switches to the color photo.
So what I'm trying to do is pre load the images with some javascript, but I'm having trouble doing this. Below is what I have for code. Also, this is in Wordpress. Not sure if that matters.
All of the images are background images too, not hardcoded into the html. It's all background css. Thanks for any help!
<script language="JavaScript">
$('document').ready(function preloader() {
// counter
var i = 0;
// create object
imageObj = new Image();
// set image list
images = new Array();
images[0]="images/treatment_locations.jpg"
images[1]="images/community_news_events.jpg"
images[2]="images/success_stories.jpg"
images[3]="images/self_assessment.jpg"
images[4]="images/our_associates.jpg"
images[5]="images/treatment_programs.jpg"
images[6]="images/patient_portal.jpg"
images[7]="images/FAQ.jpg"
images[8]="images/what_to_expect.jpg"
// start preloading
for(i=0; i<=8; i++)
{
imageObj.src=images[i];
}
});
</script>
If you overwrite the src in each iteration, you're not giving the browser a chance to fetch the image. You probably only preload the last image.
Try:
var imageObjs = [];
$('document').ready(function preloader() {
// counter
var i = 0;
// set image list
images = new Array();
images[0]="images/treatment_locations.jpg"
images[1]="images/community_news_events.jpg"
images[2]="images/success_stories.jpg"
images[3]="images/self_assessment.jpg"
images[4]="images/our_associates.jpg"
images[5]="images/treatment_programs.jpg"
images[6]="images/patient_portal.jpg"
images[7]="images/FAQ.jpg"
images[8]="images/what_to_expect.jpg"
// start preloading
for(i=0; i<=8; i++)
{
var imageObj = new Image();
imageObj.src=images[i];
imageObjs.push(imageObj);
}
});
That's another aproach, where it stores only the images that were successfully loaded.
var imgObjs = [];
$(document).ready(function preloader() {
// images list
var images = [
'treatment_locations.jpg',
'community_news_events.jpg',
'success_stories.jpg',
'self_assessment.jpg',
'our_associates.jpg',
'treatment_programs.jpg',
'patient_portal.jpg',
'FAQ.jpg',
'what_to_expect.jpg'
];
for (var i in images) {
var img = new Image();
img.src = 'images/' + images[i];
// stores it on array after loading
img.onload = function() {
imgObjs.push(this);
};
}
});
I'm trying to give the user a preview of how an image will look when combined with another image before they upload the image (think gun shooting a bullet). I can get the image to load into an image element, but then the onload event doesn't fire (tested in chrome and firefox). I've tried using setTimeout as a dirty hack, but unfortunately bullet.image.height does not appear to be set within a relatively short space of time.
Here is an example of what I'm trying to do:
if (input.target.files && input.target.files[0]) {
var file = new FileReader();
file.onload = function (event) {
// this part works fine
var bullet = {};
bullet.id = 0;
bullet.image = new Image();
bullet.image.onload = function () {
// This never fires
bullet.offset_y = bullet.image.height / 2;
$('#modal-weapons-field-bullet').append('<option value="0">' + bullet.title + '</option>');
$('#modal-weapons-field-bullet').val(0);
};
bullet.src = event.target.result;
bullet.offset_x = 0;
bullet.title = input.target.files[0].name;
}
file.readAsDataURL(input.target.files[0]);
}
bullet.src should be bullet.image.src
I put together an image preloader which works fine, but what doesn't work is updating the status after every image that has been loaded. Instead, all images are loaded and "done" (last line) is the only thing that shows up. It does work when I use an alert instead of the innerHTML command, but that is obviously of no use. What am I doing wrong?
<div id="preloader">
<span id="preloader_status"> </span>
<script language="JavaScript">
imageObj = new Image();
images = new Array();
images[0]="bigimage.gif"
images[1]="anotherbigimage.gif"
/* and so on */
var i = 0;
var o = (images.length);
for (i=0;i<o;i++) {
var status = (Math.round(100*(i/o)));
imageObj.src=images[i];
document.getElementById("preloader_status").innerHTML = status;
}
document.getElementById("preloader_status").innerHTML = "done";
</script>
</div>
To show image load progress, you will need to hook into the onload event for the images so you can track when their loading is actually complete. Images are loaded asychronously so assigning .src only STARTS the loading of the image. It is not completed until later when the onload handler is called. Because of that, your existing code will just immediately show "done" because it isn't tracking when the images are actually done loading.
In addition, you were successively assigning a new .src value to the same image object which is going to abort the previous image loading. You need to create a new image object for each new image you are loading.
You can fix your code like this:
<div id="preloader">
<span id="preloader_status"> </span>
<script language="JavaScript">
var imageSrcs = [
"bigimage.gif",
"anotherbigimage.gif"
/* and so on */
];
function preloadImages(list, statusID) {
var img, cnt = 0;
var progress = document.getElementById(statusID);
var preloads = [];
for (var i = 0; i < list.length; i++) {
img = new Image();
img.onload = function() {
++cnt;
var loadPercent = Math.round(100*(cnt/list.length));
progress.innerHTML = loadPercent;
if (cnt == list.length) {
progress.innerHTML = "done";
}
}
img.src = list[i];
preloads.push(img);
}
}
preloadImages(imageSrcs, "preloader_status");
</script>
</div>
The for loop will happen almost instantly, because images load asynchronously; setting imageObj.src will just start the image request and move on to the next. It will not block the execution of the loop. This will cause the effect you're seeing, i.e the last line of the code is executed straight away.
I think what you're looking for is the JavaScript Image onload event, which will fire when an image has finished loading.
var image = new Image();
image.onload = function() {
// always called
alert('image loaded');
};
image.src = 'image.jpg';
Code was pinched from this article.