简体   繁体   中英

jQuery/Javascript - Run function before (document).ready for the purpose of loading an image

I am trying to get the dimensions of an image in order to resize (or size) a canvas of it's length with twice the width. (So, for a 400x800 image I want a 800x800 canvas). What I'm trying to do right now is load the image twice, once to determine it's size and another time to display it. My HTML w/ Javascript/JQuery looks like

<!DOCTYPE html>
<html>
<head>
<title>Canvas from scratch</title>
<meta charset="utf-8">

<script
    src="http://ajax.googleapis.com/ajax/libs/jquery/1/jquery.min.js"></script>
<script src="jcanvas.min.js"></script>
</head>

<body>
    <canvas id="myCanvas" width="1100" height="500">
        </canvas>
    <script>

        $("<img />").attr("src", "test1image.jpg").load(function() {
            /* This is where I'd like to load the image to get its dimensions */
        });

        $(document).ready(
                function() {


                    var imgWidth, imgHeight;
                    var imageData; 

                    var image = new Image();
                    var canvas = document.getElementById("myCanvas");
                    var ctx = canvas.getContext("2d");

                    $(image).load(function() {
                        /* This is where the image is loaded and 
                           inserted into the canvas */
                        ctx.drawImage(image, 0, 0);
                    });
                    image.src = "test1image.jpg"; 

                    imageData = ctx.getImageData(0, 0,
                            image.width,
                            );

                    /* This is just part of the image manipulation, 
                       bland right now */
                    var newImgData = ctx.createImageData(imageData.width,
                            imageData.height);
                    for ( var i = 0; i < newImgData.data.length; i += 4) {
                        newImgData.data[i + 0] = 255;
                        newImgData.data[i + 1] = 0; 
                        newImgData.data[i + 2] = 0; 
                        newImgData.data[i + 3] = 255;       
                    }
                    ctx.putImageData(newImgData, imageData.width, 0);

                });
    </script>
</body>
</html>

One thing I've kept trying but noticed is not working is trying to place the function before (document).ready, but if the (document).ready call always comes first. I can't seem to get the image to load without the canvas already being created (because it is in the (document).ready call). Can anyone explain what's going on?

Thanks.

Edit_1: I just tried adding

jQuery(window).load(function() {
            $("<img />").attr("src", "test1image.jpg").load(function() {
                imgWidth = this.width;
            });
        });

to the top of the script, but imgWidth is being declared as undefined in (document).ready.

Edit_2: So, that actually worked really well blgt. Here's the new code, and it's 100% functional. The new canvas size is exactly what I wanted, based on the image dimensions and it all works... only thing I'm thinking is that there might be one too many nested functions but I'll try to work that out on my own.

<!DOCTYPE html>
<html>
<head>
<title>Canvas from scratch</title>
<meta charset="utf-8">

<script
    src="http://ajax.googleapis.com/ajax/libs/jquery/1/jquery.min.js"></script>
<script src="jcanvas.min.js"></script>
</head>

<body>
    <canvas id="myCanvas" width="1100" height="500">
        </canvas>
    <script>
        $(document).ready(
                function() {
                    $("<img>").attr("src", "test1image.jpg").on('load', function() {
                        var imgWidth, imgHeight;
                        var imageData; 
                        var image = new Image();
                        var canvas = document.getElementById("myCanvas");
                        var ctx = canvas.getContext("2d");
                        ctx.canvas.width = this.width * 2;
                        ctx.canvas.height = this.height; 
                        $(image).on("load", function() {
                            /* This is where the image is loaded and 
                               inserted into the canvas */
                            ctx.drawImage(image, 0, 0);

                        });
                        image.src = "test1image.jpg"; 

                        imageData = ctx.getImageData(0, 0,
                                this.width,
                                this.height);

                        /* This is just part of the image manipulation, 
                           bland right now */
                        var newImgData = ctx.createImageData(imageData.width,
                                imageData.height);
                        for ( var i = 0; i < newImgData.data.length; i += 4) {
                            newImgData.data[i + 0] = 255;
                            newImgData.data[i + 1] = 0; 
                            newImgData.data[i + 2] = 0; 
                            newImgData.data[i + 3] = 255;       
                        }
                        ctx.putImageData(newImgData, imageData.width, 0);
                 });
                });
    </script>
</body>
</html>

This syntax: .load() is deprecated, use .on('load'... instead. Also, this won't delay execution of the function in .ready . Is there a reason you can't do the simple, stupid thing and just put a callback to that function inside the .on('load', handler) handler instead?

$(document).ready(function() {
         $("<img>").attr("src", "test1image.jpg").on('load', function() {
                // do stuff with dimensions

                var imgWidth, imgHeight;
                var imageData; 
                // ... etc.

         });
});

You're trying to shoehorn a synchronous sequence onto an asynchronous model, and basically you just don't want to do this.

The document ready event is supposed to fire before other assets have been loaded: http://api.jquery.com/ready/ - note it mentions exactly the case you're asking about.

In cases where code relies on loaded assets (for example, if the dimensions of an image are required), the code should be placed in a handler for the load event instead.

So you should be able to just change your code to use document.load() instead of document.ready() but this will then wait until all assets are loaded. If you only want to wait for that specific image to load, you should move the code from document.ready to the image's load event.

EDIT:

Your new code basically does the last option - moves the code into the image's load event, which is probably the best overall as it allows your code to run as soon as the particular image is ready. You can potentially make it happen sooner by pre-loading the image in an inline script before loading your JS libraries etc. which would allow the image to start downloading in parallel to other assets, rather than waiting for the document ready event to start the image loading.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM