I am trying to embed an image into a canvas so that I can draw lines over the image with the canvas. However, I can't seem to get the image to appear inside the canvas. Here's the code I have (HTML then JS):
<canvas id="myCanvas" style="border:1px solid #d3d3d3; position: relative; z-index:3; top:10em; width: 30em; height: 20em; left: 22em;"></canvas>
<img src="mapfinal.png" id="mapPic" style="display: none;"/>
javascript
var c = document.getElementById("canvas");
var ctx = c.getContext("2d");
var map = document.getElementById("mapPic");
ctx.drawImage(map, 20, 20);
Thank you so much for any help!
It could be one of two things. The most likely issue is that the image is not yet loaded before you try to draw it. To fix this, add an onload event listener to the img element to draw it once the image has loaded.
<img src="mapfinal.png" id="mapPic" onload="drawCanvas" style="display: none;"/>
<script>
function drawCanvas() {
var c = document.getElementById("canvas");
var ctx = c.getContext("2d");
var map = document.getElementById("mapPic");
ctx.drawImage(map, 20, 20);
}
</script>
The other issue might be that since the img element is set to display: none the browser isn't loading the image at all. Depending on the browser it may or may not load it. If you don't want the image to dispaly a better approach would be to create it through JavaScript.
var map = new Image();
map.onload = function() {
var c = document.getElementById("canvas");
var ctx = c.getContext("2d");
ctx.drawImage(map, 20, 20);
};
map.src = 'mapfinal.png';
Related
l believe to have a logic error in the way of which my logic is meant to find the previous coordinates of my canvas object, a moving image, and delete the frame drawn before it so that it does not duplicated the image every time it is drawn onto the canvas.
There is a reproducible demo below and l added comments where l believe the problem occurs.
var canvas = document.getElementById("c");
var ctx = canvas.getContext("2d");
var the_background = document.getElementById("the_background");
var imgTag = new Image();
var X_POS = canvas.width;
var Y_POS = 0;
imgTag.src = "http://i.stack.imgur.com/Rk0DW.png"; // load image
function animate() {
/* Error resides from here */
var coords = {};
coords.x = Math.floor(this.X_POS - imgTag);
coords.y = Math.floor(this.Y_POS - imgTag);
ctx.clearRect(coords.x, coords.y, X_POS, Y_POS);
/* To here */
ctx.drawImage(imgTag, X_POS, Y_POS);
X_POS -= 5;
if (X_POS > 200) requestAnimationFrame(animate)
}
window.onload = function() {
ctx.drawImage(the_background, 0, 0, canvas.width, canvas.height);
animate();
}
html,
body {
width: 100%;
height: 100%;
margin: 0px;
border: 0;
overflow: hidden;
display: block;
}
<html>
<canvas id="c" width="600" height="400"></canvas>
<img style="display: none;" id="the_button" src="https://i.imgur.com/wO7Wc2w.png" />
<img style="display: none;" id="the_background" src="https://img.freepik.com/free-photo/hand-painted-watercolor-background-with-sky-clouds-shape_24972-1095.jpg?size=626&ext=jpg" />
</html>
It seems logical to only clear the subset of the canvas that's changing, but the normal approach is to clear and redraw the entire canvas per frame. After the car moves, the background that's cleared underneath it needs to be filled in, and trying to redraw only that subset will lead to visual artifacts and general fussiness. Clearing small portions of the screen is a premature optimization.
Canvases can't keep track of much of anything other than pixels, so an animation is more like a flipbook of stationary frames and less like a cardboard cutout animation, where the same pieces of cardboard move along and overlap one another.
Math.floor(this.X_POS - imgTag) looks wrong -- imgTag is an image object, which doesn't make sense to subtract from a number. You may have meant to grab the x property from this.
Use image.onload to ensure the image is actually loaded before running the loop. It's a bit odd to use image tags in the DOM just to load images for a canvas. I'd do that programmatically from JS which saves some typing and makes it easier to manage the data.
const loadImg = url => new Promise((resolve, reject) => {
const img = new Image();
img.onerror = reject;
img.onload = () => resolve(img);
img.src = url;
});
const images = [
"https://img.freepik.com/free-photo/hand-painted-watercolor-background-with-sky-clouds-shape_24972-1095.jpg?size=626&ext=jpg",
"http://i.stack.imgur.com/Rk0DW.png",
];
Promise
.all(images.map(loadImg))
.then(([backgroundImg, carImg]) => {
const canvas = document.getElementById("canvas");
const ctx = canvas.getContext("2d");
const car = {x: canvas.width, y: 0};
(function update() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.drawImage(
backgroundImg, 0, 0, canvas.width, canvas.height
);
ctx.drawImage(
carImg, car.x, car.y, carImg.width, carImg.height
);
car.x -= 5;
if (car.x > 200) {
requestAnimationFrame(update);
}
})();
})
.catch(err => console.error(err))
;
<canvas id="canvas" width="600" height="400"></canvas>
<!DOCTYPE html>
<html>
<head>
<title></title>
</head>
<body>
<canvas id="spriteCanvas" width="500" height="500">
<img id="coin" width="440" height="40" src="coin.png">
</canvas>
</body>
</html>
I tried placing an image inside a canvas element, but it won't display on the browser. I know the image tag works because it's displayed if I place it outside of the canvas element. Also, if I inspect the canvas element, I can see that the image is inside, but its dimensions are 0 by 0. Can somebody explain why this isn't working?
EDIT: My original code added the image through javascript, but it wouldn't show on the canvas. It was giving me the same problems as above. But I just realized I was missing "onload".
original code:
var coinImage = new Image();
coinImage.src = "coin.png";
var sCanvas = document.getElementById('spriteCanvas');
function Sprite(canvas, width, height, image){
this.context = canvas.getContext("2d");
this.width = width;
this.height = height;
this.image = image;
}
Sprite.prototype.render = function() {
var that = this;
this.context.drawImage(that.image, 0, 0);
}
function init() {
var coin = new Sprite(sCanvas, 100, 100, coinImage);
coin.render();
}
init();
editted code:
var coinImage = new Image();
coinImage.src = "coin.png";
var sCanvas = document.getElementById('spriteCanvas');
function Sprite(canvas, width, height, image){
this.context = canvas.getContext("2d");
this.width = width;
this.height = height;
this.image = image;
}
Sprite.prototype.render = function() {
var that = this;
this.context.drawImage(that.image, 0, 0);
}
coinImage.onload = function () {
var coin = new Sprite(sCanvas, 100, 100, coinImage);
coin.render();
}
This isn't how a <canvas> tag works. If you want your image to appear in your canvas, you will have to use JavaScript to place the pixels of the image into your canvas.
<canvas>s are exactly what they state: canvases. They are an element for you to draw on programmatically. If you just want to display an image on a page, you don't need a canvas, you just need the <img> tag. In fact, elements should not be placed in <canvas>.
Take a look at CanvasRenderingContext2D.drawImage() and this tutorial: HTML5 Canvas Image Tutorial.
And this snippet:
var canvas = document.getElementById("painting"),
ctx = canvas.getContext("2d"),
image = new Image();
image.onload = function() {
ctx.drawImage(image, 30, 50);
};
image.src = "http://cdn.sstatic.net/Sites/stackoverflow/img/sprites.png?v=10a9e8743fb0";
<canvas id="painting" width="300" height="300"></canvas>
To draw an image on a canvas, use the following method:
drawImage(image,x,y)
If the image you want to draw is not in the DOM already you can load an image directly from a URL with a few lines of javascript.
function loadAndDrawImage(url)
{
// Create an image object. This is not attached to the DOM and is not part of the page.
var image = new Image();
// When the image has loaded, draw it to the canvas
image.onload = function()
{
// draw image...
}
// Now set the source of the image that we want to load
image.src = url;
}
loadAndDrawImage("http://www---.png");
I am trying to add images to canvas using fabric.js. I want to add a image every time the button is clicked. The image is stored in my computer. When the image is added to the canvas, I would like to be able to drag it over the canvas.
Here is my javascript code:
function addimage1() {
var canvas = new fabric.Canvas('c');
var img = document.createElement("img");
img.src = url_1;
img.height = 50;
img.width = 100;
//optionally set a css class on the image
// var class_name = "foo";
// img.setAttribute("class", class_name);
var imgInstance = new fabric.Image(img, {
left: 100,
top: 100,
angle: 30,
opacity: 0.85
});
canvas.add(imgInstance);
//document.getElementById("resizable").appendChild(img);
//document.body.appendChild(img);
}
and here is the html code for button and canvas:
<div class="description">
<canvas id="c" width="710" height="600" style="background-color: #ffffff" ></canvas>
</div>
What am I doing wrong so the image wont be displayed?
I'm currently working on a game to teach myself HTML5 and Javascript, etc.
Originally I just had static canvases in the HTML body but it became a pain to pass around to my objects, etc. Basically it's easier for me to let each object just create its own as needed.
However, I don't know how to layer them properly like I had before. Now I have have my different canvases stacked atop of each other (my background sits above the player icon and below the objects to avoid).
How do I do this? I know it's related to the z-index (maybe innerHTML) but I'm very n00bish with HTML Javascript.
Thanks!
<canvas id="pointsCanvas"
style="z-index: 40;
position:absolute;
left:0px;
top:0px;
">
This text is displayed if your browser does not support HTML5 Canvas.
</canvas>
<canvas id="menuCanvas"
style="z-index: 50;
position:absolute;
left:0px;
top:0px;
">
This text is displayed if your browser does not support HTML5 Canvas.
</canvas>
I had this.
Now I'm trying this:
this.canvasElement = document.createElement('canvas')
Add them to a container element with its position set to relative (preferably create a rule, not an inline style like in this example):
<div id="container" style="position:relative"></div>
Then add canvases with their position set to absolute and left/top to 0:
var canvas = document.createElement("canvas");
canvas.width = 500;
canvas.height = 400;
canvas.style.cssText = "position:absolute;left:0;top:0";
// add to container
document.getElementById("container").appendChild(canvas);
The first canvas added will be at the bottom, the last on top.
You can use z-indexes but it's better just to create and add canvases in the order you want, knowing first is bottom etc. (imo).
Demo:
var canvas = document.createElement("canvas");
canvas.width = 500;
canvas.height = 400;
canvas.style.cssText = "position:absolute;left:0;top:0";
var ctx = canvas.getContext("2d");
ctx.font = "80px sans-serif";
ctx.fillText("BOTTOM", 10, 120);
// add to element
document.getElementById("container").appendChild(canvas);
// SECOOND CANVAS
var canvas2 = document.createElement("canvas");
canvas2.width = 500;
canvas2.height = 400;
canvas2.style.cssText = "position:absolute;left:0;top:0";
var ctx2 = canvas2.getContext("2d");
ctx2.font = "80px sans-serif";
ctx2.fillStyle = "blue";
ctx2.fillText("TOP", 16, 120);
// add to element
document.getElementById("container").appendChild(canvas2);
#container {position:relative}
<div id="container"></div>
A more traditional method is to have one canvas display multiple (layered) objects.
To do this you can create an array containing the definitions of each of your objects:
var gameObjects=[];
var gameObjects.push({
type: 'rect',
x:50, y:50,
width:100, height:75,
fill: 'red'
});
... and so on ...
Then for each game frame, you clear the canvas and use the definitions-array to draw the game objects in their new position.
// move the rect 5 pixels rightward
gameObjects[0].x += 5;
context.clearRect(0,0,canvas.width,canvas.height);
for(var i=0;i<gameObjects.length;i++){
var obj=gameObjects[i];
if(i.type='rect'){ drawRect(obj); }
}
function drawRect(r){
context.fillStyle=r.fill;
context.fillRect(r.x,r.y,r.width,r.height);
}
Layering
To do layering, you can add a z-index property to each of your gameObjects. It's not a z-index like a traditional html/css z-index. Instead it just lets you sort your gameObjects into any order (layers) you need.
var gameObjects.push({
type: 'rect',
x:50, y:50,
width:100, height:75,
fill: 'red',
zIndex=3
});
// sort the array by zIndex to apply layering
gameObjects.sort(function(a,b){return a.zIndex - b.zIndex});
// and now draw the "relayered" objects in the array
for(var i=0;i<gameObjects.length;i++){
var obj=gameObjects[i];
if(i.type='rect'){ drawRect(obj); }
}
I have an image background in my HTML5 canvas.
var canvas = new fabric.Canvas('#canvas1');
canvas.setBackgroundImage(
'http://fabricjs.com/assets/jail_cell_bars.png',
canvas.renderAll.bind(canvas)
);
How to set dimensions of my canvas (width, height) to the dimensions of the background image?
Thanks.
I think the above answer does not use fabric.js, it uses normal canvas.
When you use fabric.js and its Fabric.Canvas class, the code should be:
image.onLoad = function() {
var fabric_canvas = new fabric.Canvas('canvas1');
fabric_canvas.setDimensions({width:image.width, height:image.height});
};
In my case,
var canvas = new fabric.Canvas("test_fabric");
canvas.setDimensions({width:800, height:200});
The result is:
<canvas id="test_fabric" width="800" height="200" class="lower-canvas" style="position: absolute; width: 800px; height: 200px; left: 0px; top: 0px; -webkit-user-select: none;"></canvas>
Both canvas.width and canvas.style.width are set.
These work as well!
canvas.setWidth(500);
canvas.setHeight(400);
You can use CSS or dom properties to set the dimensions of your canvas. If you know the dimensions of your image, you can do it in a stylesheet:
#canvas1 { width: XXXpx; height: YYYpx; }
Or in the dom:
<canvas id="canvas1" width="XXX" height="YYY"></canvas>
If the image is dynamic and want to set the dimensions in JS, you do something like this:
var image = new Image()
image.src = 'http://fabricjs.com/assets/jail_cell_bars.png';
image.onLoad = function () {
var canvas = document.getElementById('canvas1');
canvas.width = image.width;
canvas.height = image.height;
};