0

I am relatively new to w3 schools and the canvas element but now I want to be able to draw images on the canvas. I looked on w3 schools and the only example they used included an img tag in html that was retrieved in javascript with the getElementById() function. I was wondering if there was any better way to do this using only js. In case it isn't clear here is what I was referring to I have an example below.

Image to use:

<p>Canvas:</p>
<canvas id="myCanvas" width="250" height="300" style="border:1px solid #d3d3d3;">
Your browser does not support the HTML5 canvas tag.</canvas>

<script>
var c=document.getElementById("myCanvas");
var ctx=c.getContext("2d");
var img=document.getElementById("scream");
ctx.drawImage(img,10,10);
</script>

So far the only functional methods I have found involve using an tag in html.

  • 2
    What do you mean by "a better way"? What is wrong with looking something up by ID? Can you give an example of what you're trying to avoid? ("A better way" also calls for speculation and/or opinion, which can get your question flagged. So be careful and ask more specific questions if possible.) – squid314 Feb 20 '14 at 23:25
  • W3 Skoolz is the darkside – Bryce Easley Feb 20 '14 at 23:27

3 Answers3

1

Well, you need to retrieve the canvas reference somehow, and this is how it's done, actually. I'm not sure if I understand your statement "using only js", because this is JavaScript, just interacting with HTML elements.

What you could do is creating your canvas element from JavaScript, like this answer shows

function createContext(width, height) {
    var canvas = document.createElement('canvas');
    canvas.width = width; // where 'width' is a value
    canvas.height = height; // where 'height' is a value
    return canvas.getContext("2d");
}
Community
  • 1
  • 1
Natan Streppel
  • 5,759
  • 6
  • 35
  • 43
  • I'm sorry I realize that js only is not entirely accurate, what I meant to ask was whether there is a way to add an image to javascript without ever using the tag in html. – user2669119 Feb 21 '14 at 04:08
1

There are several ways in JavaScript to "know about" an element which exists in your page.

  1. document.getElementById
  2. Depending on your document structure, you can walk the DOM: document.body.children[0].children[3].children[1] (Obviously, this is pretty ugly and not likely what you looking for.)
  3. document.getElementsByTagName('canvas')[2] to get the third <canvas> in your page (remember that arrays are zero-indexed).
  4. As @Streppel suggested, you can create the element, hold on to the JavaScript variable and then attach it to the page.
  5. document.querySelector("canvas[width=250][height=300]") to use CSS to look up your element.
squid314
  • 1,394
  • 8
  • 9
1

You can create an image dynamically without touching the DOM. But be aware of that image loading is asynchronous so you need to model your application to handle callbacks when image loaded (or failed or aborted).

For this reason you may want to consider an image loader if you are loading many images (see my profile for an example of one loader - there are more out there to suit your taste).

But in case you want to load the images yourselves - this is how you can do it:

// create the image element
var img = new Image;

// attach functions (callbacks) to handle image when loaded (or failed)
img.onload = myImageHandler;
img.onerror = myErrorHandler;

// set source last to start loading
img.src = myImageUrl;

Now the image will be loaded and myImageHandler() will be called (assuming success). From here you continue your code:

function myImageHandler() {

    // object 'this' represents the loaded image - use that if you load
    // many images and share the handler

    // draw image onto canvas (assuming ctx is defined as context)
    ctx.drawImage(this, 0, 0);

    // continue code from here...
}

I'm not showing the error-handler but it is basically the same as above just that you handle the error showing a message to user or have some fallback.

If you need to load many images you will need to keep track of the images loaded and not. It's fortunately not so much more complicated:

// setup array with URLs and one to hold the image objects
var imageURLs = [url1, url2, url, ...],
    images = [],
    count = imageURLs.length,
    i = 0, url;

// define a common handler
function loaded() {

    // decrease counter
    count--;

    // when 0 all images has loaded
    if (count === 0) {
        nextStepInCode(); // pseudo function
    }
}

// invoke image loading:
for(; url = imageURLs[i++];) {

    // create a new image and push to element stack
    var img = new Image;
    images.push(img);

    // set handler
    img.onload = loaded;

    // invoke loading
    img.src = url;
}

// code continues here before images has loaded, but you need
// to continue in the callback (loader)

Also here you need to add an error handler which also decrease the counter (or you won't be able to continue). An onabort handler is also a pluss.

Hope this helps.