How to draw a background image on an HTML5 canvas - javascript

I'm working on my first HTML5 Canvas game. I am trying to put in a background image, and I don't know how to do it. The game will change backgrounds throughout levels, but I think I understand how to make that happen. However, if I just try to draw an image, then it appears above my title text. Any ideas how to fix this? I don't think the CSS method will work, because the background will change. Here is my code:
<!DOCTYPE html>
<html>
<head>
<title>How Well Do You Know Your Swedish?</title>
</head>
<body>
<canvas width="640" height="480" id="game" style="display: block; margin-left: auto; margin-right: auto; border: 1px solid black;" Your Browser is not compatible with this game. We recommend Google Chrome, Mozilla Firefox, or Opera.></canvas>
<script>
var game_canvas = document.getElementById("game");
var game_context = game_canvas.getContext("2d");
var swedishflagbg = new Image();
swedishflagbg.src = "resources/images/swedishflagbg.png";
swedishflagbg.onload = function() {
game_context.drawImage(swedishflagbg, 0, 0);
}
game_context.fillStyle = "#000000";
game_context.font = "35px Ubuntu";
game_context.textAlign = "center";
game_context.textBaseline = "top";
game_context.fillText("How Well Do You Know Your Swedish?", 320, 0);
</script>
</body>
</html>
I am new to JavaScript, and even newer to the HTML5 Canvas.

Extending from comment:
The "why":
Because the background image is drawn in an onload event, which will happen "later", while text is drawn immediately.
So the text is drawn first, and then sometimes later the image is drawn, thus causing the text to be covered.
The "how":
Depending on how "dynamic" the background image is, you can consider:
use CSS background-image on cancas/canvas container, and use className/classList to switch between different backgrounds;
put an <img> tag underneath the canvas, and change its src property;
use an additional "background" canvas underneath the current one, so you can draw the game content in current one, and draw the (probably not frequently-updated) background in the new one.
Credit of idea 1 and 2 goes to #markE :)

First things:
Check the size of your image. It should be equivalent to the size of the canvas.
context.drawImage can also take width and height parameter for the image.
Syntax: context.drawImage(img, x, y, width, height);
After editing, it should look like this
let game_canvas = document.getElementById("game");
let game_context = game_canvas.getContext("2d");
let swedishflagbg = new Image();
swedishflagbg.src = "resources/images/swedishflagbg.png";
swedishflagbg.onload = function() {
game_context.drawImage(swedishflagbg, 0, 0, game_canvas.width, game_canvas.height);
}
game_context.fillStyle="#000000";
game_context.font="35px Ubuntu";
game_context.textAlign="center";
game_context.textBaseline="top";
game_context.fillText("How Well Do You Know Your Swedish?", 320, 0);

To anyone who is still facing the problem of background image overlaying text (Image above text), I thought "why not drawing text inside onload function after loading bg image!?"
And it worked!! The browser (Or whatever) loads image first and load my text above image.
<canvas width="534" height="104" id="game" style="display: block; margin-left: auto; margin-right: auto; border: 1px solid black;" Your Browser is not compatible with this game. We recommend Google Chrome, Mozilla Firefox, or Opera.></canvas>
<script>
let game_canvas = document.getElementById("game");
let game_context = game_canvas.getContext("2d");
let swedishflagbg = new Image();
swedishflagbg.src = "./img/logo1.png";
swedishflagbg.onload = function() {
game_context.drawImage(swedishflagbg, 0, 0, game_canvas.width, game_canvas.height);
game_context.fillStyle = "#000000";
game_context.font = "35px Ubuntu";
game_context.textAlign = "center";
game_context.textBaseline = "top";
game_context.fillText("How Well Do You Know Your Swedish?", 320, 0);
}
</script>

Related

HTML text inside Canvas

I need to render an image on which I have put some HTML text on it and then the user to be able to download the image with the text as an image or even better as a pdf.
The certText element is taken from a TinyMCE variable, where the user each time uses different HTML tags within the text.
So it could be
"Hello user, how are you"
or
"Hi there, great that you succeed on the certification".
Starting from the image option I have created below code but Canvas do no translate the HTML tags.
I have read that with Canvas it's not possible to render the HTML tags, but is there any other alternative to succeed this.
The code is used on a Laravel project that I have made.
var p = document.getElementById("certificate");
var ptx = p.getContext("2d");
var imgp = document.getElementById("certificateEmpty");
var txtp = document.getElementById("certText").innerHTML;
imgp.onload = function(){
ptx.drawImage(imgp, 0, 0);
ptx.font = "48px Nunito";
ptx.fillText(txtp, 150, 1000);
};
imgp.src = "{{$attendees[0]->certBLocation}}";
What are you trying to achive when you say "render html tags"?
Do you mean you want to style the text that is drawn on the canvas?
If so, you have to use canvas functions to set what the text will look like.
In the below example using your code, I use "fillStyle" to set the drawing fill colour in which the text will be drawn.
var p = document.getElementById("certificate");
var ptx = p.getContext("2d");
var imgp = document.getElementById("certificateEmpty");
var txt = document.getElementById("certText");
var txtp = txt.innerHTML;
imgp.onload = function(){
ptx.drawImage(imgp, 0, 0, p.width, p.height);
var styles = window.getComputedStyle(txt);
ptx.fillStyle = styles.color;
//ptx.font = styles.font; // Doesn't seem to work in firefox.
ptx.font = styles['font-weight']+" "+styles['font-size']+" "+styles.fontFamily; // Access properties array style because of hyphens.
ptx.fillText(txtp, 0, 100);
};
imgp.src = "https://www.gravatar.com/avatar/7b67c827ee1671ba3b43f4aebf6794fb?s=200";
img, canvas {
width: 200px;
height: 200px;
}
#certText {
color: #ff0000;
font-weight: bold;
font-size: 40px;
}
<img id="certificateEmpty"/>
<canvas id="certificate"></canvas>
<div id="certText">
some text
</div>
Text drawn on the canvas looks squashed on my screen (Ubuntu/Chrome), not sure why.

compare 2 canvas elements for similarity and return result

I'm new to js and html5 so here's what I'm doing : I'm working on a game that helps in teaching illustrator shortcuts, the firts level consist of 2 canvas one with an already existing image and the other blank and ready for user to draw on, on ctrl + s press(sure I disabled it's default action using jquery) I want to compare the content of those 2 canvas elements. I've found Image similarity api from deepai.org very useful and accurate, but it only accepts url or input="file" content, so I'm trying to find a way to upload (maybe) the drawn canvas as an image to a server and get the url like this : https://server.com/myaccount/images/img1.png and since i only upload one image I can pass that static url to the api in addition to the original image which will also have a static url so hopefully it compares.
I made a solution that works without a server. But I couldn't make it work in an online code repo like jsfiddle. So I put it on my own server for you to check. http://paulyro.com/paul/deepai/
For convenience I put everything in one file. Of course it would make sense to save the JS in a separate file. But I let that up to you.
For explanation: the red square in a black frame is the canvas. I generate two images and add them to the page. Then I send those images to the deepAI server when you press the button. You will only need one generated img, but for testing purpose I made 2.
Let me know if this is what you were looking for. Of course I expect you to adapt this solution to your exact needs ;)
This is the code:
<!DOCTYPE HTML>
<html>
<head>
<meta charset="utf-8">
<title>DeepAiDemo</title>
<script src="https://cdnjs.deepai.org/deepai.min.js"></script>
<style rel="stylesheet">
canvas {
border: 1px solid black;
}
</style>
</head>
<body>
<canvas id="canvas1" width="200" height="200"></canvas>
<button name="button" onClick="load()">Press me</button>
<div style="position:absolute;left:400px; top:30px; height: 354px;" id="messages">Result will get here</div>
<script type="text/javascript">
(async function() {
var can = document.getElementById('canvas1');
var ctx = can.getContext('2d');
// create green canvas and make it an image
ctx.fillStyle = "green";
ctx.fillRect(75, 75, 50, 50);
var img = new Image();
img.src = can.toDataURL();
document.body.appendChild(img);
// create red canvas and make it an image
ctx.fillStyle = "red";
ctx.fillRect(75, 75, 50, 50);
var img2 = new Image();
img2.src = can.toDataURL();
document.body.appendChild(img2);
})()
const load = async () => {
document.getElementById('messages').innerHTML = "Waitng for response...";
deepai.setApiKey('xxxxxxxxxxxxxx');
var images = document.getElementsByTagName('img');
console.log("amount images: "+images.length);
console.log(images[0]);
console.log(images[1]);
var resp = await deepai.callStandardApi("image-similarity", {
image1: images[0],
image2: images[1],
});
console.log("response: ");
console.log(resp);
document.getElementById('messages').innerHTML = "Distance: " + resp.output.distance; //resp.output.distance contains the number from the server.
};
</script>
</body>
</html>
Cheers,
Paul

How to change the shape of the canvas itself?

I'm working on a project and I use createCapture(VIDEO); using p5js libraries, to get the video using my web camera. Then I store every image of that capture (from < video> element) and draw it in a canvas in the function draw().
I was wondering if it's possible the change the shape of the canvas(such as a mirror for example (oval or circle)).
Again, notice that I don't want to crop the image but the canvas itself.
Here is some code:
function setup(){
canvas = createCanvas(640, 480); //480p
canvas.parent('editedCanvas-container');
originalCapture = createCapture(VIDEO);
originalCapture.parent('originalVideo-container');
originalCapture.size(640, 480); //480p
}
function draw(){
frame = image(originalCapture, 0, 0, width, height);
}
If somebody has a clue please let me know.
You can change the shape of your canvas tag by applying css rules,
So try this css code
#canvasObject {
border: 2px solid black;
width: 200px;
height: 150px;
border-radius: 100px / 50px;
}
<canvas id="canvasObject">
</canvas>
For more info about how to achieve shapes in css, please refer this amazing post for css-tricks

Cannot save canvas with draggable object

I'm trying to save my HTML canvas to file which I can successfully do, but it's not saving any objects I've dragged into the canvas.
So, by using the Draggable JQuery I can happily move my object around screen and place it ontop of my canvas. When I save the canvas using the Canvas.ToDataURL() it does not save my dragged objects (and also does something strange to my canvas in the jsFiddle, it appears to change the colour of my canvas?).
To see a "working" example, please visit my jsFiddle http://jsfiddle.net/JVSFS/74/
Please simply drag the green box over the blue box and click the save button. The result will be shown underneath (just an orange box).
HTML
<canvas id="MyCanvas" class="canvas"></canvas>
<div class="popup_click">
<div id="popup_title">Drag</div>
</div>
<asp:HiddenField ID="hideMe" runat="server" />
<asp:Button runat="server" OnClick="ClickMe" Text="Click" OnClientClick="SaveMe()" />
<button onclick="SaveMe()">Try it</button>
<p>Results: </p>
<img id="myImage" />
JavaScript
$(document).ready(function () {
$('.popup_click').show(0).draggable();
});
function SaveMe() {
var canvas = document.getElementById("MyCanvas");
var context = canvas.getContext("2d");
context.fillStyle = "orange";
context.fillRect(0, 0, 100, 100);
var image = canvas.toDataURL("image/png");
document.getElementById("myImage").src = image;
document.getElementById("hideMe").value = image;
}
CSS
.popup_click {
background: #80FF80;
width: 50px; }
.canvas {
width: 100px;
height: 100px;
background-color: #0FC;
}
How can I get the dragged object to save? I assume I have to tell the Canvas that the object is part of it's context but no idea how and my own searches came up with nothing.
From https://developer.mozilla.org/en-US/docs/HTML/Canvas/Drawing_DOM_objects_into_a_canvas
You can't just draw HTML into a canvas. Instead, you need to use an SVG image containing the content you want to render. To draw HTML content, you'd use a element containing the HTML, then draw that SVG image into your canvas.
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
var data = "<svg xmlns='http://www.w3.org/2000/svg' width='200' height='200'>" +
"<foreignObject width='100%' height='100%'>" +
"<div xmlns='http://www.w3.org/1999/xhtml' style='font-size:40px'>" +
"<em>I</em> like <span style='color:white; text-shadow:0 0 2px blue;'>cheese</span>" +
"</div>" +
"</foreignObject>" +
"</svg>";
var DOMURL = self.URL || self.webkitURL || self;
var img = new Image();
var svg = new Blob([data], {type: "image/svg+xml;charset=utf-8"});
var url = DOMURL.createObjectURL(svg);
img.onload = function() {
ctx.drawImage(img, 0, 0);
DOMURL.revokeObjectURL(url);
};
img.src = url;
That's because your draggable object isn't in the canves.
They are simple html elements.
It'll save only the objects whose created with canvas methods.
Any way to create html elements on canvas you have to use svg.
Mozilla show nice way to to this but you need to get all the css to inline css before.
mozilla explanation
Anyway with using svg on you canvas you won't be able to use toDataUrl because of security policy.

HTML5 Canvas: How to make a loading spinner by rotating the image in degrees?

I am making a loading spinner with html5 canvas. I have my graphic on the canvas but when i rotate it the image rotates off the canvas. How do I tell it to spin the graphic on its center point?
<!DOCTYPE html>
<html>
<head>
<title>Canvas test</title>
<script type="text/javascript">
window.onload = function() {
var drawingCanvas = document.getElementById('myDrawing');
// Check the element is in the DOM and the browser supports canvas
if(drawingCanvas && drawingCanvas.getContext) {
// Initaliase a 2-dimensional drawing context
var context = drawingCanvas.getContext('2d');
//Load the image object in JS, then apply to canvas onload
var myImage = new Image();
myImage.onload = function() {
context.drawImage(myImage, 0, 0, 27, 27);
}
myImage.src = "img/loading.png";
context.rotate(45);
}
}
</script>
</head>
<body>
<canvas id="myDrawing" width="27" height="27">
</canvas>
</body>
</html>
Here is the complete working example:)
<!DOCTYPE html>
<html>
<head>
<title>Canvas Cog</title>
<script type="text/javascript">
var cog = new Image();
function init() {
cog.src = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABsAAAAbCAYAAACN1PRVAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAABK1JREFUeNqMVt1ZGzkUvVfS4IW1l8GO82w6IBXE7mCpAFMB+Pt4Z6iApALcAe4AU0HoAJfg7BPYHinnXmmciX+y0YdmJHnQ0bk/R5cvh5cUyFPwRD4EChgEvGWMB36R3+JaiTkmD5gOs8yNb25uLlerFf1pM2yIGA82TEY7xow1oj4GBU6S6yywPNG4JwDH+XGv0Whs7ndN8n97mmPsLCSYgy7ImPQE/pFDyAF+7L0fgTNFUDBcLal90taD1doQ/T6NT9DnW8zkT+jJuQVYukG3hifCVk/L3JOxMBa8VVlSp9MhHKLaB+zpNo1fdgEpmByuMqUAV5viOQLwXNax9KBAFNEEpN1pUwnQmvl6aTza6zNjrCKaymeyOdYAMgfg18iG4T/qw+AC94zvpzDjcwqOXo3VGH26H0xMZ7jPxgT0R2zUi4BYt6bAfEbJvJFZKA4ODgZ5nhcJLE9mk35X21vWC/TXKmiwr2xszoQd/PQv3t/QCzY2twpqBpb5FKOp+hCgzWaTWq0W1Xx0ij5An9WC5VtiLMwvNBrVaSGMvQk5jHQVPN7sb0HzAtE+QJrNgrcUNEARieWCut0ugR0tl8sKcJ5Ahc3jRviPK8ZGTaaBwGKyT+gTiwM4a3Jrba6MbeVXo5F4kp9shn29ndUYC9vLirGDXzRhrYhD8DME5Hkg22df5rDYS/RXmVIsaP/Q/SXs600YnifTjbeSWliEdTYb3QyTqYfdDKTL4B1KS6tVqf6SgGq3P9BvZGpvNIrPCgVKZlGlCDQDxJiCjVppCab05DJHzb+b1Gm36X80cVjLuzozexs0f6IgRkA5XRhzIixRL1+IzhwdHVHrn1Y9oXe1i10aKT6bGGhg1CKK+cT0zCGCs0oXTIogybJMw/779//o48duMvnO9rzLn+Kz8wgS5Shqo4njpCoOQA5Ajb8adHh4SMvVghaLhYb/HsBip88krNVISSEigOlhjmi0LziNhr6wOsgO9C1339vbGznnNAU2AM9Svk235cqKieKGkldAf7DGvTrjnjJnzyQoMu0ZTuZgUqvmlYR+f39XIE4uqCX1E/rDZpCYmKwOOmivAfYK9KF1AM7EdG4uAMLAOjmQideQXOJQkyUisqYiFRhtSFbxCxj8do0T30dmTvLhC+an0MZZVBHX09tBTG4qFigZEJEChjTIEwtRik81Qa7uOQU0IrYAe7FRjqYw6SlYjgAyN1GmHsFIGPfVnxzFuFITKEkfYK+oWZ5qKlIkcZ7UE92oXBmeIgIxtAO5UtSHqo9uiLW+sme5ejSIRASeAFR4LYy8MMzL1aq3EYWzJF28BgMEzGYpBkrMKelgl+P6uTcVY8NjLYyYPwMTCcufSaouH6al9xNJcjC82vDb9uVZKbrWIumNO+waVsu1TCC+Wxcg6xaSpsZSYM2wLO9/U8qZWH+wztQnsfAxV/E3MIKZVf1FsmJVV8mamhEmxZ0X7sSsABsGv1tZJGejmptU7FBUDYzPAXQBwFEEl+9+stFEroJEci2ELwIMmZuWoSTE9DYYcWVCjlJrZWMpeBhlAEqBiulPE84S3ixU5gSTwGGOdyEVNJXxA8nPevshwABHktBS1YoQ+QAAAABJRU5ErkJggg=='; // Set source path
setInterval(draw,10);
}
var rotation = 0;
function draw(){
var ctx = document.getElementById('myCanvas').getContext('2d');
ctx.globalCompositeOperation = 'destination-over';
ctx.save();
ctx.clearRect(0,0,27,27);
ctx.translate(13.5,13.5); // to get it in the origin
rotation +=1;
ctx.rotate(rotation*Math.PI/64); //rotate in origin
ctx.translate(-13.5,-13.5); //put it back
ctx.drawImage(cog,0,0);
ctx.restore();
}
init();
</script>
</head>
<body>
<canvas width="27" height="27" id="myCanvas"></canvas>
</body>
</html>
rotate turns the canvas(?) around your current position, which is 0, 0 to start. you need to "move" to your desired center point, which you can accomplish with
context.translate(x,y);
after you move your reference point, you want to center your image over that point. you can do this by calling
context.drawImage(myImage, -(27/2), -(27/2), 27, 27);
this tells the browser to start drawing the image from above and to the left of your current reference point, by have the size of the image, whereas before you were starting at your reference point and drawing entirely below and to the right (all directions relative to the rotation of the canvas).
since your canvas is the size of your image, your call to translate will use the same measurement, (27/2), for x and y coordinates.
so, to put it all together
// initialization:
context.translate(27/2, 27/2);
// onload:
context.rotate(Math.PI * 45 / 180);
context.drawImage(myImage, -(27/2), -(27/2), 27, 27);
edit: also, rotation units are radians, so you'll need to translate degrees to radians in your code.
edits for rearranging stuff.
For anyone else looking into something like this, you might want to look at this script which does exactly what was originally being requested:
http://projects.nickstakenburg.com/spinners/
You can find the github source here:
https://github.com/staaky/spinners
He uses rotate, while keeping a cache of rectangles which slowly fade out, the older they are.
I find another way to do html loading spinner. You can use sprite sheet animation. This approach can work both by html5 canvas or normal html/javascript/css. Here is a simple way implemented by html/javascript/css.
It uses sprite sheet image as background. It create a Javascript timer to change the background image position to control the sprite sheet animation. The example code is below. You can also check the result here: http://jmsliu.com/1769/html-ajax-loading-spinner.html
<html>
<head><title></title></head>
<body>
<div class="spinner-bg">
<div id="spinner"></div>
</div>
<style>
.spinner-bg
{
width:44px;
height:41px;
background: #000000;
}
#spinner
{
width: 44px;
height: 41px;
background:url(./preloadericon.png) no-repeat;
}
</style>
<script>
var currentbgx = 0;
var circle = document.getElementById("spinner");
var circleTimer = setInterval(playAnimation, 100);
function playAnimation() {
if (circle != null) {
circle.style.backgroundPosition = currentbgx + "px 0";
}
currentbgx -= 44; //one frame width, there are 5 frame
//start from 0, end at 176, it depends on the png frame length
if (currentbgx < -176) {
currentbgx = 0;
}
}
</script>
</body>

Categories

Resources