loading...

re: Why does the image not display on the canvas? VIEW POST

TOP OF THREAD FULL DISCUSSION
re: Hmm... where are you loading the image from? It might be that it can't find it. I've tried it in this codepen and it seems to work. Check whether ...

I am serving on a local (file:) protocol in a plain html file. And I check the request, and it's perfectly fine (also, wouldn't I get ERR : FILE_NOT_FOUND or something like that in console?) if you feel inclined, I can reply w/ a text representation of the folder system w/ the functions I have.
Also, I don't know if this helps, but I also tried doing:

i.addEventListener("load",onload);

to see if the results would change.

So I've tried it in my local machine opening the html file directly in the browser and it is working. Maybe the problem is elsewhere in your code. How are you getting the canvas context? Can you show the entire code, or upload it to a gist in GitHub if it is too large?

Yea, this is the code:

<!DOCTYPE html>

<html lang="en">
    <head>
        <title>Rose's Adventure&trade;</title>
        <meta charset="utf-8">
        <style>
            * {
                image-rendering:pixelated;
                -webkit-image-rendering:pixelated;
                -moz-image-rendering:pixelated;
                -o-image-rendering:pixelated;
                user-select:none;
                -webkit-user-select:none;
                -moz-user-select:none;
                -o-user-select:none;
            }
            body {
                background-color:#1c1c1c;
                background:#1c1c1c;
            }
            img {
                display:none;
                image-rendering:pixelated;
            }
            canvas {
                background-color:black;
                background:black;
                image-rendering:pixelated;
                width:90vw;
                height:90vh;
            }
        </style>
    </head>
    <body>
        <canvas id="screen"></canvas>
        <script>

            // Disable context menu
            document.oncontextmenu = function() {
                return false;
            };

            // Get components for the game screen
            let c = document.getElementById("screen")
            let s = c.getContext("2d");

            // Game loop
            const gameLoop = function() {
                drawBg();
                drawRoom();
            };

            // Start the game
            const startGame = function() {
                c.style.cursor = "none";
                c.onclick = null;
                drawBg("#ffffff");
                let logo = sprites.logo;
                let logoPath = "textures/"+sprites.logo+".png";
                drawImg(
                    logo,
                    /*vw(90)/2-img(logoPath).width/2,*/ 300,
                    /*vh(90)/2-img(logoPath).height/2*/ 300
                );
            };

            // Current display information
            let curr_sprite = "idle";
            let currentHealth = 3;
            let maxHealth = 3;
            let facing = "right";
            let room = 0;
            let roseX = 0;
            let roseY = 0;

            // Get the sprites
            let sprites = {
                logo: "logo",
                rose: {
                    idle: {
                        right: "RoseRight",
                        left: "RoseLeft"
                    },
                    jump: {
                        right: "RoseJumpRight",
                        left: "RoseJumpLeft"
                    },
                    hover: {
                        right: "RoseHoverRight",
                        left: "RoseHoverLeft"
                    }
                },
                vortex: {
                    right: "VortexRight",
                    left: "VortexLeft"
                }
            };

            // Get the images from sources
            const img = function(src=null,onload=null) {
                const i = new Image();
                i.addEventListener("load",onload);
                i.src = src;
                return i;
            };

            // Draw the background
            const drawBg = function(color="#3f49ff") {
                c.style.backgroundColor = color;
                c.style.background = color;
                return c.style.backgroundColor;
            };

            // Draw an image onto the canvas
            const drawImg = function(src=null,x=0,y=0,width=undefined,height=undefined) {
                if(src === null) {
                    return false;
                }
                let i = null;
                const draw = function() {
                    s.drawImage(i,x,y,width,height);
                };
                i = img("textures/"+src+".png",function() {
                    alert();
                    draw();
                });
                return true;
            };

            // View height
            const vh = function(v) {
                let h = Math.max(
                    document.documentElement.clientHeight,
                    window.innerHeight || 0
                );
                return (v*h)/100;
            };

            // View width
            const vw = function(v) {
                let w = Math.max(
                    document.documentElement.clientWidth,
                    window.innerWidth || 0
                );
                return (v*w)/100;
            };

            // Get the lowest point of measurement, and add an amount
            /*const addLast = function(x=0,y=0) {
                let lowest = (x/);
            };*/

            // Draw each room
            const drawRoom = function() {
                let scene = rooms[room];
                let tileX = 0;
                let tileY = 0;
                for(const layer of scene) {
                    let bh = vh(90)/scene.length;
                    for(const tile of layer) {
                        let bw = vw(90)/layer.length;
                    }
                    tileY += bh+1;
                }
            };

            // Start the game when the user clicks on the canvas when it is ready
            document.addEventListener("DOMContentLoaded",function() {
                c.onclick = startGame;
                c.style.cursor = "pointer";
            });

            // Make a new tile
            const gtile = function(attributes=null) {
                const defaultConfig = {
                    texture: null,
                    spawnpoint: false,
                    name: "",
                    collisionX: false,
                    collisionY: false,
                    scaleX: 1,
                    scaleY: 1,
                    pain: 0,
                    kills: false,
                    knockbackX: 0,
                    knockbackY: 0
                };
                if(attributes === null || !Boolean(attributes)) {
                    return {...defaultConfig};
                }
                let tileObj = {...defaultConfig};
                for(const attr of Object.keys(attributes)) {
                    if(attr === "collision") {
                        tileObj.collisionX = tileObj.collisionY = attributes[attr];
                    }
                    if(attr === "knockback") {
                        tileObj.knockbackX = tileObj.knockbackY = attributes[attr];
                    }
                    if(attr === "scale") {
                        tileObj.scaleX = tileObj.scaleY = attributes[attr];
                    }
                    tileObj[attr] = attributes[attr];
                }
                return tileObj;
            };

            // Tiles for each room
            const tiles = [
                gtile({
                    spawnpoint: false,
                    name: "air"
                }),
                gtile({
                    spawnpoint: true,
                    name: "spawnpoint"
                }),
                gtile({
                    collision: true,
                    texture: "Dirt",
                    name: "dirt"
                }),
                gtile({
                    collision: true,
                    texture: "Grass",
                    name: "grass"
                })
            ];

            // Room information
            const rooms = [
                [
                    [0,0,0,0,0,0,0,0,0,0],
                    [0,0,0,0,0,0,0,0,0,0],
                    [0,0,0,0,0,0,0,0,0,0],
                    [2,2,2,2,0,0,0,0,0,1],
                    [2,2,2,2,2,2,2,2,2,2]
                ]
            ];

        </script>
    </body>
</html>

as I said, the alert fires, but not the drawing

I've seen the problem now, it's still in your drawImg function. The i that you are passing to your draw function is null, even if you reassign it further on.

const drawImg = function (src = null, x = 0, y = 0, width = undefined, height = undefined) {
    if (src === null) {
        return false;
    }
    let i = null;
    const draw = function () {
        s.drawImage(i, x, y, width, height);
    };
    i = img("textures/" + src + ".png", function () {
        alert();
        draw();
    });
    return true;
};

you should rewrite it instead to have i defined when you pass it to the function

const drawImg = function (src = null, x = 0, y = 0, width = undefined, height = undefined) {
    if (src === null) {
        return false;
    }
    const i = img("textures/" + src + ".png", () => {
        s.drawImage(i, x, y, width, height)
    })
    return true;
};

How does this change the program in any way, once i is assigned for the first time vs when it's reassigned? Is it just JavaScript that does this, or do other languages do this too? And why do languages do this? It'd be really cool to know what the bug was, and what happens in the language (provided you know anything about what happens).
And thanks again for the help!

Actually nevermind, after some more testing, your original code worked as well. I think that the problem is that you are passing width and height to context.drawImage when they are undefined, which probably makes the function scale the image to 0x0 or something.

Huh, it still doesn't draw nothing? But it's not null now, if it was before, I removed the display:none for images, and I added two lines to the onload function for debugging:

(document.body || document.head.parentNode).appendChild(i);
console.log(i);

and it logs the image element, and appends the image, the canvas doesn't work.

Here are my results:
<img src="textures/logo.png">
I even drew another image, using the console and it was added to the document fine, logged normally as the element, but again, no result on the canvas, what the hell happens with the canvas, and this is weird, because instead of anti-aliasing being the issue, it's now images not showing up.

            // Exactly as you wrote it
            const drawImg = function(src=null,x=0,y=0,width=undefined,height=undefined) {
                if(src === null) {
                    return false;
                }
                const i = img("textures/"+src+".png",() => {
                    (document.body || document.head.parentNode).appendChild(i);
                    console.log(i);
                    s.drawImage(i,x,y,width,height);
                });
                return true;
            };

But if this approach doesn't work I might start from scratch again, but I don't know what the most effective method is.

Yeah, my bad. Look at my previous comment, the problem isn't with the reassignment, it's with passing width and height to s.drawImage when they are undefined.

No, because doesn't undefined keep the original parameter

function f(x="Hi") {
console.log(x);
}

f(undefined);

result in:
Hi?

Yeah, but your default value for height and width is undefined. The function drawImage has several configurations of optional arguments, and it probably checks the length of the arguments to choose which strategy to apply. In your case, it is receiving five arguments, so it understands that it has to scale the image, but the scales are undefined.

You can try this to see what I mean:

const f = (...args) => console.log(args.length)
f(1, 2, 3) // 3
f(1, 2, 3, undefined, undefined) // 5

Ok, but how, then, can I resize the image (if I want or need) , but leave the parameters blank if the input value for that doesn't exist? Is there just no way to do that?

You could take the height and the width from the image if they are not provided.

const drawImg = function (src = null, x = 0, y = 0, width, height) {
    if (src === null) {
        return false;
    }
    let i = null;
    const draw = function () {
        const w = width || i.width
        const h = height || i.height
        s.drawImage(i, x, y, w, h);
    };
    i = img("textures/" + src + ".png", function () {
        alert();
        draw();
    });
    return true;
};

Ok, thanks, as I said, the default is it uses the image size, and the image did not appear when I ommited the width or height variables from the function call.......
For reference, this is what the image looks like:
postimg.cc/3kcW6Lqc

Nevermind, I ommited the width and height parameters from the s.drawImage function, and it still didn't appear.

code of conduct - report abuse