Repeating image in a canvas with responsive height - javascript

I'm trying to create a canvas where I have an image as a background that repeats horizontally and adapts the height automatically.
I've managed to repeat the background image following the x-axis but I'm unable to make the height responsive.
This is my code so far:
const cvs = document.getElementById("canvas");
const ctx = cvs.getContext("2d");
const bg = new Image();
bg.src = "http://lorempixel.com/100/100";
const draw = () => {
const ptrn = ctx.createPattern(bg, "repeat-x");
ctx.fillStyle = ptrn;
ctx.fillRect(0, 0, canvas.width, canvas.height);
requestAnimationFrame(draw);
};
draw();
<!DOCTYPE html>
<html>
<head>
<title>Test</title>
</head>
<body>
<canvas id="canvas" width="1000" height="200"></canvas>
<script src="index.js"></script>
</body>
</html>
TLDR: I would like to be able to have an image within my canvas that repeats horizontally and its height is responsive.
Thanks in advance.

Hopefully the explanation in the comments answers your question. Feel free to ask for clarification.
const cvs = document.getElementById("canvas");
const ctx = cvs.getContext("2d");
// First stretch the canvas so we can get
// the full size of teh browser window
cvs.style.height = '100vh';
cvs.style.width = '100vw';
// Now adjust actual canvas size to match
const {width, height} = cvs.getBoundingClientRect();
cvs.height = height;
cvs.width = width;
const bg = new Image();
// Should always wait for onload
// before drawing to prevent race condition.
bg.onload = ()=>{
var x=0;
while(x < cvs.width){
ctx.drawImage(bg, x, 0, 100, cvs.height);
x += bg.width;
}
// draw the image a bunch of times
// var x=0, y=0;
// while(x < cvs.width && y < cvs.height){
// ctx.drawImage(bg, x, y);
// x += bg.width;
// if(x > cvs.width){
// x = 0;
// y += bg.height;
// }
// }
};
bg.src = "http://lorempixel.com/100/100";
<canvas id="canvas"></canvas>
<script src="index.js"></script>

If I got it right you want to fill the height and repeat horizontally, is that correct?
const cvs = document.getElementById("canvas");
const ctx = cvs.getContext("2d");
var bg = new Image();
bg.src = "http://lorempixel.com/100/100";
var tempCanvas = document.createElement("canvas"),
tCtx = tempCanvas.getContext("2d");
var imgWidth = 200;
var imgHeight = 200;
const draw = () => {
tempCanvas.width = imgWidth;
tempCanvas.height = imgHeight;
tCtx.drawImage(bg, 0, 0, 100, 100, 0, 0, imgWidth, imgHeight);
const ptrn = ctx.createPattern(tempCanvas , "repeat-x");
ctx.fillStyle = ptrn;
ctx.fillRect(0, 0, canvas.width, canvas.height);
requestAnimationFrame(draw);
};
bg.onload = () => {
draw();
}
<!DOCTYPE html>
<html>
<head>
<title>Test</title>
</head>
<body>
<canvas id="canvas" width="1000" height="200"></canvas>
<script src="index.js"></script>
</body>
</html>

try setting up the image size to match the canvas size just like that:
bg.src = "http://lorempixel.com/200/200";
Cheers! :)

Related

HTML Canvas doesn't diplay rectangle if written to off screen canvas

I have tried to create an HTML page with a full screen canvas and I can draw to this fine. If I create a second "off screen" canvas to draw on and display on the main canvas I do not see anything.
My code is:
var canvas;
var canvas_ctx;
var off_canvas = document.createElement('canvas');
var off_canvas_ctx;
init();
drawTree();
function init() {
canvas = document.getElementById('treeCanvas');
if (canvas.getContext) {
canvas_ctx = canvas.getContext("2d");
window.addEventListener('resize', resizeCanvas, false);
window.addEventListener('orientationchange', resizeCanvas, false);
resizeCanvas();
}
off_canvas.width = 5000;
off_canvas.height = 5000;
off_canvas_ctx = off_canvas.getContext('2d');
}
function resizeCanvas() {
var cWidth = window.innerWidth;
var cHeight = window.innerHeight - 3;
var imgData = canvas_ctx.getImageData(0, 0, cWidth, cHeight);
// Resize original canvas
canvas.width = cWidth;
canvas.height = cHeight;
// Copy back to resized canvas
canvas_ctx.putImageData(imgData, 0, 0);
}
function drawTree() {
canvas_ctx.fillStyle = "#FF0000";
canvas_ctx.fillRect(0, 0, 150, 75);
off_canvas_ctx.fillStyle = "#FF0000";
off_canvas_ctx.fillRect(0, 0, 150, 75);
resizeCanvas();
}
<div align="center">
<canvas id="treeCanvas" width="200" height="100">
Your browser does not support the canvas element.
</canvas>
</div>
My "drawTree()" function currently draws the same thing to both canvas contexts and then calls "resizeCanvas()" in order to update the display.
If I use the line
var imgData = canvas_ctx.getImageData(0, 0, cWidth, cHeight);
in "resizeCanvas()", the rectangle displays but if I try to use the image data from the off screen canvas with the line
var imgData = off_canvas_ctx.getImageData(0, 0, cWidth, cHeight);
then nothing is displayed. Can anyone see what I am doing wrong?
My mistake, in the "init()" function i was calling "resizeCanvas()" before i had got the context to the second canvas, this seemed to mess it up for the rest of the session.
canvas_ctx = canvas.getContext("2d");
off_canvas.width = 5000;
off_canvas.height = 5000;
off_canvas_ctx = off_canvas.getContext('2d');
Moving the block up appears to have fixed the problem.

Rotate an image on top of another canvas image

Currently, I am making a game and in need of making the image rotate toward the cursor. I am using node but the image is in a js tag in the HTML file that uses ctx to draw the image.
If I put a ctx.rotate(angle); pretty much anywhere it will rotate everything; player, map, etc. I need help so that only the player is rotated
this is a simplified version of my code:
<canvas id="ctx" width="200" height="200"></canvas>
<script>
//game
var ctx = document.getElementById("ctx").getContext("2d");
var WIDTH = 200;
var HEIGHT = 200;
var Img = {};
//player
Img.player = new Image();
Img.player.src = '/client/img/player.png';
var Player = function(/*node*/){
ctx.drawImage(Img.player, ...);
}
//map
Img.map = new Image();
Img.map.src = '/client/img/map.png';
//display everything
setInterval(function(){
ctx.clearRect(0,0,200,200);
drawMap();
for(var i in Player.list)
Player.list[i].draw();
},1000/60);
//functions
//move map so that player is always in the middle
var drawMap= function(){
var x = WIDTH/2 - Player.list[/*node*/].x;
var y = HEIGHT/2 - Player.list[/*node*/].y;
ctx.drawImage(Img.map,x,y);
}
</script>
Here's an example of what you may be looking for
const ctx = document.getElementById("ctx").getContext("2d");
const WIDTH = 500,
HEIGHT = 500;
document.getElementById("ctx").height = HEIGHT;
document.getElementById("ctx").width = WIDTH;
var Player = {
x: 50,
y: 55,
angle: 0
}
document.addEventListener("mousemove", (event) => {
var x = event.clientX - Player.x,
y = event.clientY- Player.y,
angle = Math.atan2(y,x);
Player.angle = angle
})
function draw() {
window.requestAnimationFrame(draw);
ctx.clearRect(0, 0, WIDTH, HEIGHT);
ctx.save();
ctx.translate(Player.x, Player.y);
ctx.rotate(Player.angle);
ctx.translate(-Player.x, -Player.y);
ctx.fillRect(Player.x, Player.y, 20, 20);
ctx.restore();
ctx.fillRect(150, 50, 20, 20);
}
draw();
<canvas id="ctx"></canvas>
jsfiddle here
Hope this helps!

Html5 canvas animation leaves a trail

I'm trying to make a little game to play around with canvas. I've decided to go for Flappy Bird as there are plenty of examples online. My goal was to make the game "responsive" for all devices. If you open it in a mobile or whichever screen, you should be able to play it normally.
For this purpose I drew a background image within the canvas that will adapt the height to the screen's height and repeat it through the x-axis.
The issue I'm having is that, when I animate the bird, this one leaves a trail behind it.
As like so:
An easy fix would be clearing the canvas as explained in this post:
Canvas image leaves weird trail when moving left
But it isn't possible because of the way I'm painting my background (I paint it once and repaint it if it resizes).
Question
How do I avoid this image trail with a static background? Is it maybe possible to have like a false static background that doesn't need to be repainted?
I obviously want to do it in the canvas, without needing to have an image in the html.
This is the code with the main functionality so that you can take a look:
const cvs = document.getElementById("canvas");
const ctx = cvs.getContext("2d");
cvs.style.height = "100vh";
cvs.style.width = "100vw";
var bird = new Image();
var bg = new Image();
bird.src = "https://lh3.googleusercontent.com/prntPuix7QxlhKXx6IBtTxv7PrdEJtmzFJ4mopScNS1_klze86BVNy3PqHbQn2UQ4JyJdix3XQ=w128-h128-e365";
bg.src = "https://opengameart.org/sites/default/files/bg_5.png";
let gravity = 1;
birdPositionY = 10;
birdPositionX = 50;
const draw = () => {
ctx.drawImage(bird, birdPositionX, birdPositionY);
birdPositionY += gravity;
birdPositionX += 3;
requestAnimationFrame(draw);
};
const resizeCanvas = () => {
const {
width,
height
} = cvs.getBoundingClientRect();
cvs.height = height;
cvs.width = width;
let x = 0,
y = 0;
while (x < cvs.width && y < cvs.height) {
ctx.drawImage(bg, x, y, 360, cvs.height);
x += bg.width;
}
};
bg.onload = () => {
resizeCanvas();
};
window.addEventListener("resize", resizeCanvas, false);
draw();
<!DOCTYPE html>
<html>
<head>
<title>Flappy Bird</title>
<meta name="viewport" content="width=device-width, user-scalable=no" />
<style>
html {
overflow: hidden;
}
body {
margin: 0;
}
canvas {
width: 100vw;
height: 100vh;
}
</style>
</head>
<body>
<canvas id="canvas"></canvas>
<script src="index.js"></script>
</body>
</html>
Hope it did make sense!
Thanks in advance!
Draw your background on a canvas that you will keep off-screen, then draw this canvas every frame on your visible one before you draw your moving parts.
const cvs = document.getElementById("canvas");
const ctx = cvs.getContext("2d");
// our backround canvas that we won't append in the doc ("off-screen")
const background = cvs.cloneNode();
const bg_ctx = background.getContext('2d');
cvs.style.height = "100vh";
cvs.style.width = "100vw";
var bird = new Image();
var bg = new Image();
bird.src = "https://lh3.googleusercontent.com/prntPuix7QxlhKXx6IBtTxv7PrdEJtmzFJ4mopScNS1_klze86BVNy3PqHbQn2UQ4JyJdix3XQ=w128-h128-e365";
bg.src = "https://opengameart.org/sites/default/files/bg_5.png";
let gravity = 1;
birdPositionY = 10;
birdPositionX = 50;
const draw = () => {
// first draw the background canvas
ctx.drawImage(background, 0,0);
// then your persona
ctx.drawImage(bird, birdPositionX, birdPositionY);
birdPositionY += gravity;
birdPositionX += 3;
requestAnimationFrame(draw);
};
const resizeCanvas = () => {
const {
width,
height
} = cvs.getBoundingClientRect();
// resize both canvases
cvs.height = background.height = height;
cvs.width = background.width = width;
let x = 0,
y = 0;
while (x < cvs.width && y < cvs.height) {
// draw on the off-screen canvas
bg_ctx.drawImage(bg, x, y, 360, cvs.height);
x += bg.width;
}
};
bg.onload = () => {
resizeCanvas();
draw();
};
window.addEventListener("resize", resizeCanvas, false);
<!DOCTYPE html>
<html>
<head>
<title>Flappy Bird</title>
<meta name="viewport" content="width=device-width, user-scalable=no" />
<style>
html {
overflow: hidden;
}
body {
margin: 0;
}
canvas {
width: 100vw;
height: 100vh;
}
</style>
</head>
<body>
<canvas id="canvas"></canvas>
<script src="index.js"></script>
</body>
</html>
I think you could just call resizeCanvas in your draw loop to redraw the background.
EDIT: Apparently that does not work. Another option is just drawing it in the draw loop like this:
const draw = () => {
ctx.clearRect(0, 0, cvs.width, cvs.height)
let x = 0, y = 0;
while (x < cvs.width && y < cvs.height) {
ctx.drawImage(bg, x, y, 360, cvs.height);
x += bg.width;
}
ctx.drawImage(bird, birdPositionX, birdPositionY);
birdPositionY += gravity;
birdPositionX += 3;
requestAnimationFrame(draw);
};
Edit: That did not work either. The other option would be to make two canvases and overlap them with one drawing the background and one drawing the bird.

Canvas background hide the rects that I added

I am new here, so please be consider.
I've created a new canvas and created a rects in the canvas , when I set a background to the canvas I have a terrible problem that The background is on the shapes
Here is the code:
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
var BB = canvas.getBoundingClientRect();
var offsetX = BB.left;
var offsetY = BB.top;
var WIDTH = canvas.width;
var HEIGHT = canvas.height;
var background = new Image();
background.src = "url_to_image";
// Make sure the image is loaded first otherwise nothing will draw.
background.onload = function(){
ctx.drawImage(background,0,0);
}
<canvas id="canvas" width=450 height=700></canvas>
Thanks
Edit:
I found in my code a function of fillStyle that change my background,
so I delete it and instead of this I put this:
var w = canvas.width;
var h = canvas.height
var img = new Image();
img.src = "http://www.girija.info/wp-content/uploads/2015/08/Paznja-Sabranost-450x700.png";
img.onload = function () {
var pattern = ctx.createPattern(img, "repeat");
ctx.fillStyle = pattern;
ctx.fillRect(0, 0, w, h);
};
//ctx.fillStyle = "#FAF7F8";
rect(0, 0, WIDTH, HEIGHT);
// redraw each rect in the rects[] array
for (var i = 0; i < rects.length; i++) {
var r = rects[i];
ctx.fillStyle = 'red';
rect(r.x, r.y, r.width, r.height);
}
But every drag of the rect (the rects loaded from stack and can be draggable) the background color of the rect change
You can set the background using the css property
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
var BB = canvas.getBoundingClientRect();
var offsetX = BB.left;
var offsetY = BB.top;
var WIDTH = canvas.width;
var HEIGHT = canvas.height;
ctx.rect(10, 10, 100, 100);
ctx.fill();
canvas.style.backgroundImage = 'url(https://picsum.photos/450/700)';
<canvas id="canvas" width=450 height=700></canvas>
var canvas = document.getElementById('canvas'),
context = canvas.getContext('2d');
background_image();
function background_image()
{
background_image = new Image();
background_image.src = 'https://image.ibb.co/kmV8kz/photodune_2359510_smiles_l_22.png';
background_image.onload = function(){
context.drawImage(background_image, 0, 0);
}
}
<canvas id="canvas" width=450 height=700></canvas>

html5 canvas mirroring objects

I wrote the following code in my text editor:
<!DOCTYPE HTML><html>
<head>
<script>
window.onload = function()
{
var canvas = document.getElementById("canvasArea");
var context = canvas.getContext("2d");
var ball = new Image();
var smallImage = "https://i.warosu.org/data/sci/img/0076/83/1448614341262.png";
var ballXPos = 75;
var ballYPos = 15;
var ballWidth = 90;
var ballHeight = 90;
var reflectAdj = 3.5;
var reflectAlpha = .4;
var reflect Y = (2*ballYPos) + (2*(ballHeight-reflectAdj));
var gradLV = context.createLinearGradient(0, 0, 0, canvas.height);
ball.onload = function()
{
gradLV.addColorStop( 0, "lightskyblue");
gradLV.addColorStop(.3, "orange");
gradLV.addColorStop(1, "blue");
context.fillStyle = gradLV;
context.fillRect(0, 0, canvs.width, canvas.height);
context.translate(0, reflectY);
context.scale(1,-1);
context.globalAlpha = reflectAlpha;
context.drawImage(ball, ballXpos, ballYpos, ballWidth, ballHeight);
}
}
</script>
</head>
<body>
<div style = "width:400px; height:210px; margin:0 auto; padding:5px;">
<canvas id = "canvasArea" width = "400" height = "210"
style = "border:2px solid black">
Your browser doesn't currently support HTML5 Canvas.
</canvas>
</div>
</body>
</html>
In this code, the canvas is supposed to show a mirrored object, but the canvas is completely blank. Can someone please tell me what I did wrong/ PLease and thank you.
Your code was full of a number of small errors, most of which were typos. You were also failing to specify the image URL as the src of the new Image() constructor.
The code below fixes these issues and provides visual output on the canvas. I'm not sure exactly what mirror effect you're going for, but hopefully this sets you on the right path.
window.onload = function() {
var canvas = document.getElementById("canvasArea");
var context = canvas.getContext("2d");
var ball = new Image();
ball.src = "https://i.warosu.org/data/sci/img/0076/83/1448614341262.png";
var ballXPos = 75;
var ballYPos = 15;
var ballWidth = 90;
var ballHeight = 90;
var reflectAdj = 3.5;
var reflectAlpha = .4;
var reflectY = (2*ballYPos) + (2*(ballHeight-reflectAdj));
var gradLV = context.createLinearGradient(0, 0, 0, canvas.height);
ball.onload = function() {
gradLV.addColorStop( 0, "lightskyblue");
gradLV.addColorStop(.3, "orange");
gradLV.addColorStop(1, "blue");
context.fillStyle = gradLV;
context.fillRect(0, 0, canvas.width, canvas.height);
context.translate(0, reflectY);
context.scale(1,-1);
context.globalAlpha = reflectAlpha;
context.drawImage(ball, ballXPos, ballYPos, ballWidth, ballHeight);
}
}
<div style = "width:400px; height:210px; margin:0 auto; padding:5px;">
<canvas id = "canvasArea" width = "400" height = "210" style = "border:2px solid black">
Your browser doesn't currently support HTML5 Canvas.
</canvas>
</div>

Categories