Hello and welcome to our community! Is this your first visit?
Register
Enjoy an ad free experience by logging in. Not a member yet? Register.
Page 1 of 2 12 LastLast
Results 1 to 15 of 16
  1. #1
    New Coder
    Join Date
    Nov 2012
    Posts
    10
    Thanks
    6
    Thanked 0 Times in 0 Posts

    Images not displayed when iterated

    Hi all,

    I'm not a professional programmer and fairly new to JavaScript, so please don't laugh. Here goes nothing.

    I'm trying to display 10 images pulled from a database using PHP/MySQL next to eachother (to use as source canvas for a scrolling routine in another canvas).

    This works (assume all variables and arrays have been defined properly - I'm merely showing the important part):

    Code:
    img[0] = new Image();
    img[0].onload = function() {
     		ctxsrc.drawImage(img[0], sourcepointer, 0, width[0], height);
    		sourcepointer=sourcepointer+width[0];
    };
    img[0].src = imgsrc[0];
    
    img[1] = new Image();
    img[1].onload = function() {
     		ctxsrc.drawImage(img[1], sourcepointer, 0, width[1], height);
    		sourcepointer=sourcepointer+width[1];
    };
    img[1].src = imgsrc[1];
    But this gives a Type Error in the drawImage line:

    Code:
    for (i=0; i<number; i++) {
    	img[i] = new Image();
    	img[i].onload = function() {
     		ctxsrc.drawImage(img[i], sourcepointer, 0, width[i], height);
    		sourcepointer=sourcepointer+width[i];
    	};
    	img[i].src = imgsrc[i];
    }
    I'm baffled! How come?
    Last edited by Luke7268; 11-17-2012 at 12:18 PM.

  • #2
    Senior Coder
    Join Date
    Apr 2011
    Location
    London, England
    Posts
    2,120
    Thanks
    15
    Thanked 354 Times in 353 Posts
    Number is a keyword (or type) in JS so I wouldn't use that as a variable name.

    So width is an array but height isn't? Personally, I would not use width or height as identifiers either.

    check that width[i] is a number, rather than a string or something else, so that it can be ADDED to sourcepointer.
    Last edited by AndrewGSW; 11-17-2012 at 07:31 PM.
    "I'm here to save your life. But if I'm going to do that, I'll need total uninanonynymity." Me Myself & Irene.
    Validate your HTML and CSS

  • Users who have thanked AndrewGSW for this post:

    Luke7268 (11-18-2012)

  • #3
    New Coder
    Join Date
    Nov 2012
    Posts
    10
    Thanks
    6
    Thanked 0 Times in 0 Posts
    Thank you for your reply so far!

    There's no array for height as the height of all pictures is the same (they are automatically resized to the canvas height, while preserving the aspect ratio).

    Unfortunately changing the code into this:

    Code:
    for (i=0; i<numberofpics; i++) {
    	img[i] = new Image();
    	img[i].onload = function() {
     		ctxsrc.drawImage(img[i], sourcepointer, 0, widthpic[i], heightcanvas);
    		sourcepointer=sourcepointer+widthpic[i];
    	};
    	img[i].src = imgsrc[i];
    }
    ...gives the very same issue.

    widthpic definitely contains a value, as...

    Code:
    img[0] = new Image();
    img[0].onload = function() {
     		ctxsrc.drawImage(img[0], sourcepointer, 0, widthpic[0], heightcanvas);
    		sourcepointer=sourcepointer+widthpic[0];
    };
    img[0].src = imgsrc[0];
    
    img[1] = new Image();
    img[1].onload = function() {
     		ctxsrc.drawImage(img[1], sourcepointer, 0, widthpic[1], heightcanvas);
    		sourcepointer=sourcepointer+widthpic[1];
    };
    img[1].src = imgsrc[1];
    
    for (i=0; i<numberofpics; i++) {
    	img[i] = new Image();
    	img[i].onload = function() {
     		ctxsrc.drawImage(img[i], sourcepointer, 0, widthpic[i], heightcanvas);
    		sourcepointer=sourcepointer+widthpic[i];
    	};
    	img[i].src = imgsrc[i];
    }
    ...shows. This displays two pictures. The loop however generates an error.

    ctxsrc.drawImage(img[i], sourcepointer, 0, widthpic[i], heightcanvas); <= Uncaught TypeError: Type error (repeated 9 times)
    Last edited by Luke7268; 11-17-2012 at 08:04 PM. Reason: Mistake in code

  • #4
    Senior Coder
    Join Date
    Apr 2011
    Location
    London, England
    Posts
    2,120
    Thanks
    15
    Thanked 354 Times in 353 Posts
    I think this is maybe a closure issue. the onload events don't fire until all the loops have finished, in which case i is 9 (or 10) for all of the images.

    Code:
    for (i=0; i<numberofpics; i++) {
    	img[i] = new Image();
    	img[i].onload = function() {
                    var keepi = i;
     		ctxsrc.drawImage(img[keepi], sourcepointer, 0, widthpic[keepi], heightcanvas);
    		sourcepointer=sourcepointer+widthpic[keepi];
    	};
    	img[i].src = imgsrc[i];
    }
    Otherwise, I would try setting the .src before assigning the onload events.
    "I'm here to save your life. But if I'm going to do that, I'll need total uninanonynymity." Me Myself & Irene.
    Validate your HTML and CSS

  • Users who have thanked AndrewGSW for this post:

    Luke7268 (11-18-2012)

  • #5
    New Coder
    Join Date
    Nov 2012
    Posts
    10
    Thanks
    6
    Thanked 0 Times in 0 Posts
    No luck yet, but:

    Code:
    for (i=0; i<numberofpics; i++) {
    	img[i] = new Image();
    	img[i].src = imgsrc[i];
    	img[i].onload = function() {
    		var keepi = i;
     		ctxsrc.drawImage(img[keepi], sourcepointer, 0, widthpic[keepi], heightcanvas);
    		sourcepointer=sourcepointer+widthpic[keepi];
    	};
    }
    ...gives only 6 (?!) errors. There's definitely something funny going on, and it seems that it has to do with the loading times...

  • #6
    Senior Coder
    Join Date
    Apr 2011
    Location
    London, England
    Posts
    2,120
    Thanks
    15
    Thanked 354 Times in 353 Posts
    If it is related to loading times then try reducing the number of images temporarily to see if it behaves better. If this is the case then creating timeouts may not help as it (I'm assuming) needs to wait until the first drawImage completes before starting the second, etc..

    Hopefully this is not the issue as it may prove tricky to stagger the image-drawing.

    Try outputting the variable information each time within the loop:

    Code:
    console.log(sourcepointer); // etc.
    and examine this information within the browser's console (F12).

    Disclaimer: I haven't done much work with canvas.
    "I'm here to save your life. But if I'm going to do that, I'll need total uninanonynymity." Me Myself & Irene.
    Validate your HTML and CSS

  • Users who have thanked AndrewGSW for this post:

    Luke7268 (11-18-2012)

  • #7
    Senior Coder
    Join Date
    Apr 2011
    Location
    London, England
    Posts
    2,120
    Thanks
    15
    Thanked 354 Times in 353 Posts
    You may need to remember the values for sourcepointer as well:

    Code:
    for (i=0; i<numberofpics; i++) {
    	img[i] = new Image();
    	img[i].onload = function() {
                    var keepi = i, keepsp = sourcepointer;
     		ctxsrc.drawImage(img[keepi], keepsp, 0, widthpic[keepi], heightcanvas);
    		sourcepointer=sourcepointer+widthpic[keepi];
    	};
    	img[i].src = imgsrc[i];
    }
    otherwise it might be trying to draw things outside of the canvas.
    "I'm here to save your life. But if I'm going to do that, I'll need total uninanonynymity." Me Myself & Irene.
    Validate your HTML and CSS

  • Users who have thanked AndrewGSW for this post:

    Luke7268 (11-18-2012)

  • #8
    New Coder
    Join Date
    Nov 2012
    Posts
    10
    Thanks
    6
    Thanked 0 Times in 0 Posts
    No luck I'm afraid...

    I also tried:

    Code:
    for (i=0; i<numberofpics; i++) {
    	img[i] = new Image();
    	img[i].onload = function() {
                    var keepi = i, keepsp = sourcepointer;
     		ctxsrc.drawImage(img[keepi], keepsp, 0, widthpic[keepi], heightcanvas);
    		keepsp =keepsp +widthpic[keepi];
    	};
    	img[i].src = imgsrc[i];
    }
    ...but that didn't work either.

  • #9
    Senior Coder
    Join Date
    Apr 2011
    Location
    London, England
    Posts
    2,120
    Thanks
    15
    Thanked 354 Times in 353 Posts
    My last attempt:

    Code:
    for (i=0; i<numberofpics; i++) {
    	img[i] = new Image();
    	img[i].onload = function() {
                    var keepi = i, keepsp = sourcepointer;
     		ctxsrc.drawImage(img[keepi], keepsp, 0, widthpic[keepi], heightcanvas);
    	};
            sourcepointer = sourcepointer + widthpic[i];
    	img[i].src = imgsrc[i];
    }
    "I'm here to save your life. But if I'm going to do that, I'll need total uninanonynymity." Me Myself & Irene.
    Validate your HTML and CSS

  • Users who have thanked AndrewGSW for this post:

    Luke7268 (11-18-2012)

  • #10
    New Coder
    Join Date
    Nov 2012
    Posts
    10
    Thanks
    6
    Thanked 0 Times in 0 Posts
    I read a bit about asynchronous script execution and functions in functions. Then I read about callback hell. I read and read, but the whole concept of functions inside functions was making me dizzy.

    Until I found this page:
    http://callbackhell.com/

    I still didn't understand half of it, but one line hit me: "Write small modules that each do one thing, and assemble them into other modules that do a bigger thing. You can't get into callback hell if you don't go there."

    Then I came up with this:
    Code:
    var loadPictureOnCanvas = function (index, url, sourcepointer, widthpic, heightcanvas) {
    	img[index] = new Image();
    	img[index].onload = function() {
     		ctxsrc.drawImage(img[index], sourcepointer, 0, widthpic, heightcanvas);
    	};
    	img[index].src = url;
    }
    
    for (i=0; i<numberofpics; i++) {
    	loadPictureOnCanvas(i, imgsrc[i], sourcepointer, widthpic[i], heightcanvas);
    	sourcepointer=sourcepointer+widthpic[i];
    }
    It works like a charm, and is so much easier to understand than functions inside functions, a concept which I really can't get my head around yet, especially not when people start nesting them infinitely.

  • #11
    New Coder
    Join Date
    Nov 2012
    Posts
    10
    Thanks
    6
    Thanked 0 Times in 0 Posts
    This script works a lot better, as it uses callback (I think) in a way I think I understand. I've tried some more convoluting syntaxes (I believe this is called callback hell), but I can't get my head around them.

    This loads and displays all 10 images fine. However, the copy to the new canvas fails because JS is trying to copy the images from the source canvas while they are not displayed yet. However, all of them have neatly been preloaded, as the copying function is not executed unless the source canvas is ready and contains all pictures.

    When I insert alerts though, the source canvas clearly shows that the pictures display there *after* the (still empty) source canvas has been copied to the target canvas. Is there some time between loading and displaying? Apparently. If so, how do I check on that?

    Code:
    var loadPictureOnCanvas = function (index, url, sourcepointer, widthpic, heightcanvas) {
    	img[index] = new Image();
    	img[index].onload = function() {
     		contextsrc.drawImage(img[index], sourcepointer, 0, widthpic, heightcanvas);
    	};
    	img[index].src = url;
    	alert(index);
    }
    
    var copyCanvas = function() {
    	contextdest.drawImage(canvassrc, 0, 0, widthcanvas, heightcanvas, 0, 0, widthcanvas, heightcanvas);
    	alert('thenCopy');
    }
    
    var makeSourceCanvas = function() {
    	for (i=0; i<numberofpics; i++) {
    		loadPictureOnCanvas(i, imgsrc[i], sourcepointer, widthpic[i], heightcanvas);
    		sourcepointer=sourcepointer+widthpic[i];
    	}
    	alert('makeSource');
    }
    
    copyCanvas(makeSourceCanvas());
    The alerts give 0 1 2 3 4 5 6 7 8 9 makeSource thenCopy... but only after I click thenCopy away do the pictures display in the source canvas. Which explains why the target canvas stays empty.
    Last edited by Luke7268; 11-18-2012 at 01:32 AM.

  • #12
    Senior Coder
    Join Date
    Apr 2011
    Location
    London, England
    Posts
    2,120
    Thanks
    15
    Thanked 354 Times in 353 Posts
    Code:
    copyCanvas(makeSourceCanvas());
    // this passes the result of the function makeSourceCanvas to your function copyCanvas, but makeSourceCanvas doesn't return a result (other than null or undefined - the default).

    ..but your function
    Code:
    var copyCanvas = function() {
    isn't expecting to receive any data; that is, it has no parameter(s).
    "I'm here to save your life. But if I'm going to do that, I'll need total uninanonynymity." Me Myself & Irene.
    Validate your HTML and CSS

  • Users who have thanked AndrewGSW for this post:

    Luke7268 (11-18-2012)

  • #13
    New Coder
    Join Date
    Nov 2012
    Posts
    10
    Thanks
    6
    Thanked 0 Times in 0 Posts
    I really appreciate all the hints.

    However:

    Code:
    var loadPictureOnCanvas = function (index, url, sourcepointer, widthpic, heightcanvas) {
    	img[index] = new Image();
    	img[index].onload = function() {
     		contextsrc.drawImage(img[index], sourcepointer, 0, widthpic, heightcanvas);
    	};
    	img[index].src = url;
    	alert(index);
    }
    
    var copyCanvas = function(callback) {
    	contextdest.drawImage(canvassrc, 0, 0, widthcanvas, heightcanvas, 0, 0, widthcanvas, heightcanvas);
    	alert('thenCopy');
    	return callback;
    }
    
    var makeSourceCanvas = function(callback) {
    	for (i=0; i<numberofpics; i++) {
    		loadPictureOnCanvas(i, imgsrc[i], sourcepointer, widthpic[i], heightcanvas);
    		sourcepointer=sourcepointer+widthpic[i];
    	}
    	alert('makeSource');
    	return callback;
    }
    
    copyCanvas(makeSourceCanvas(callback));
    ...gives exactly the same issue.

    Now I have never worked with asynchronous code before, so I may be entirely missing the purpose of callbacks... Apparently I do, else this would have worked.

  • #14
    New Coder
    Join Date
    Nov 2012
    Posts
    10
    Thanks
    6
    Thanked 0 Times in 0 Posts
    As I'm scrolling pixel by pixel anyway I just gave up on the whole thing and decided to just start scrolling whether the source canvas' contents have been copied or not. In a worst-case-scenario, I miss two pixels or so, but this is not detectable by the human eye.

    Code:
    window.requestAnimFrame = (function(callback) {
    	return window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame || window.oRequestAnimationFrame || window.msRequestAnimationFrame ||
    	function(callback) {
    		window.setTimeout(callback, 1000 / 60);
    	};
    })();
       
    var heightcanvas = $heightcanvas;
    var widthcanvas =  $widthcanvas;
    var topleft = widthcanvas;
    var numberofpics = $zoekfotosaantal;
    var totalwidth = $totalwidth;
    
    var imgsrc = new Array();
    var widthpic = new Array();
    var img = new Array();
    
    imgsrc[0] = '$fotourl[0]';
    widthpic[0] = $widthnew[0];
    	
    imgsrc[1] = '$fotourl[1]';
    widthpic[1] = $widthnew[1];
    	
    imgsrc[2] = '$fotourl[2]';
    widthpic[2] = $widthnew[2];
    	
    imgsrc[3] = '$fotourl[3]';
    widthpic[3] = $widthnew[3];
    	
    imgsrc[4] = '$fotourl[4]';
    widthpic[4] = $widthnew[4];
    
    imgsrc[5] = '$fotourl[5]';
    widthpic[5] = $widthnew[5];
    	
    imgsrc[6] = '$fotourl[6]';
    widthpic[6] = $widthnew[6];
    	
    imgsrc[7] = '$fotourl[7]';
    widthpic[7] = $widthnew[7];
    	
    imgsrc[8] = '$fotourl[8]';
    widthpic[8] = $widthnew[8];
    
    imgsrc[9] = '$fotourl[9]';
    widthpic[9] = $widthnew[9];
    	
    var canvasdest = document.getElementById('myCanvasDest');
    var contextdest = canvasdest.getContext('2d');
    contextdest.fillStyle = '#000000'; 
    contextdest.fillRect(0, 0, widthcanvas, heightcanvas);  
    
    var canvassrc = document.getElementById('myCanvasSrc');
    var contextsrc = canvassrc.getContext('2d');
    contextsrc.fillStyle = '#000000'; 
    contextsrc.fillRect(0, 0, totalwidth, heightcanvas);
    
    var sourcepointer = 0;
    var scrollpointer = 0;
    var i = 0;
    
    var loadPictureOnCanvas = function (index, url, sourcepointer, widthpic, heightcanvas) {
    	img[index] = new Image();
    	img[index].onload = function() {
     		contextsrc.drawImage(img[index], sourcepointer, 0, widthpic, heightcanvas);
    	};
    	img[index].src = url;
    	// if (index==numberofpics-1) {
    	// 	alert(index);
    	// }
    }
    
    var scroll = function() {
    	contextdest.drawImage(canvassrc, scrollpointer, 0, 1, heightcanvas, widthcanvas-1, 0, 1, heightcanvas);
    	contextdest.drawImage(canvasdest, 1, 0, widthcanvas-1, heightcanvas, 0, 0, widthcanvas-1, heightcanvas);
    	// alert('thenCopy');
    	// request new frame
    	requestAnimFrame(function() {
    		scroll();
    	});
    	scrollpointer++;
    	if (scrollpointer>totalwidth) {
    		scrollpointer=0;
    	}
    }
    
    var makeSourceCanvas = function() {
    	for (i=0; i<numberofpics; i++) {
    		loadPictureOnCanvas(i, imgsrc[i], sourcepointer, widthpic[i], heightcanvas);
    		sourcepointer=sourcepointer+widthpic[i];
    	}
    	// alert('makeSource');
    }
    
    makeSourceCanvas();
    scroll(); // I still have no idea to start this *after* makeSourceCanvas is completely finished
    Still curious after a solution for starting the scroll *after* makeSourceCanvas is done...

    See the script in action at www.japanology.nl (top left corner).

  • #15
    New Coder
    Join Date
    Nov 2012
    Posts
    10
    Thanks
    6
    Thanked 0 Times in 0 Posts

    Solution found. This guy nails it down...

    This guy nails it down... http://www.impressivewebs.com/callba...ns-javascript/

    The first proper explanation about callback I see on the web that can actually be understood by stupid beginners like me. I have finally seen the light.

    After that, solving the problem was pretty easy:

    Code:
    <script>
    window.requestAnimFrame = (function(callback) {
    	return window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame || window.oRequestAnimationFrame || window.msRequestAnimationFrame ||
    	function(callback) {
    		window.setTimeout(callback, 1000 / 60);
    	};
    })();
       
    var heightcanvas = $heightcanvas;
    var widthcanvas =  $widthcanvas;
    var topleft = widthcanvas;
    var numberofpics = $zoekfotosaantal;
    var totalwidth = $totalwidth;
    
    var imgsrc = new Array();
    var widthpic = new Array();
    var img = new Array();
    
    imgsrc[0] = '$fotourl[0]';
    widthpic[0] = $widthnew[0];
    	
    imgsrc[1] = '$fotourl[1]';
    widthpic[1] = $widthnew[1];
    	
    imgsrc[2] = '$fotourl[2]';
    widthpic[2] = $widthnew[2];
    	
    imgsrc[3] = '$fotourl[3]';
    widthpic[3] = $widthnew[3];
    	
    imgsrc[4] = '$fotourl[4]';
    widthpic[4] = $widthnew[4];
    
    imgsrc[5] = '$fotourl[5]';
    widthpic[5] = $widthnew[5];
    	
    imgsrc[6] = '$fotourl[6]';
    widthpic[6] = $widthnew[6];
    	
    imgsrc[7] = '$fotourl[7]';
    widthpic[7] = $widthnew[7];
    	
    imgsrc[8] = '$fotourl[8]';
    widthpic[8] = $widthnew[8];
    
    imgsrc[9] = '$fotourl[9]';
    widthpic[9] = $widthnew[9];
    	
    var canvasdest = document.getElementById('myCanvasDest');
    var contextdest = canvasdest.getContext('2d');
    contextdest.fillStyle = '#000000'; 
    contextdest.fillRect(0, 0, widthcanvas, heightcanvas);  
    
    var canvassrc = document.getElementById('myCanvasSrc');
    var contextsrc = canvassrc.getContext('2d');
    contextsrc.fillStyle = '#000000'; 
    contextsrc.fillRect(0, 0, totalwidth, heightcanvas);
    
    var sourcepointer = 0;
    var scrollpointer = 0;
    var i = 0;
    
    var loadPictureOnCanvas = function (index, url, sourcepointer, widthpic, heightcanvas) {
    img[index] = new Image();
    img[index].onload = function() {
    contextsrc.drawImage(img[index], sourcepointer, 0, widthpic, heightcanvas);
    	if (index==9) {
    		copyCanvas();
    	}
    };
    img[index].src = url;
    alert(index);
    }
    
    var copyCanvas = function() {
    contextdest.drawImage(canvassrc, 0, 0, widthcanvas, heightcanvas, 0, 0, widthcanvas, heightcanvas);
    alert('thenCopy');
    }
    
    var makeSourceCanvas = function() {
    for (i=0; i<numberofpics; i++) {
    loadPictureOnCanvas(i, imgsrc[i], sourcepointer, widthpic[i], heightcanvas);
    sourcepointer=sourcepointer+widthpic[i];
    }
    alert('makeSource');
    }
    
    makeSourceCanvas();
    
    </script>
    The magic happens in loadPictureOnCanvas, specifically within the onload method.
    Last edited by Luke7268; 11-18-2012 at 07:19 PM.


  •  
    Page 1 of 2 12 LastLast

    Posting Permissions

    • You may not post new threads
    • You may not post replies
    • You may not post attachments
    • You may not edit your posts
    •