How to fill html5 canvas grid squares with image? - javascript

I am new to html5 canvas. I want to draw one canvas grid and fill each grid square with an image from an API response. I have following code to draw the grid but I am struggling to fill each square with image.
This is js code:
window.onload = function(){
var c= document.getElementById('canvas');
var ctx=c.getContext('2d');
ctx.strokeStyle='white';
ctx.linWidth=4;
for(i=0;i<=600;i=i+60)
{
ctx.moveTo(i,0);
ctx.lineTo(i,600);
ctx.stroke();
}
for(j=0; j<=600; j=j+60)
{
ctx.moveTo(0,j);
ctx.lineTo(600,j);
ctx.stroke();
}
}
This code helps me drawing canvas grid but how to access each square and fill it with the image. I referred links related to this but seems difficult to understand. Can somebody please help me with this?

It's hard to answer your question without knowing exactly how the image is being returned by the api response. Assuming the api response is returning the image itself (not the image data in JSON or something like that) here is a solution:
html:
<canvas id="canvas" width="600" height="600"></canvas>
javascript:
window.onload = function() {
const canvas = document.getElementById("canvas");
const ctx = canvas.getContext("2d");
ctx.strokeStyle = "green";
ctx.lineWidth = 4;
//draw grid
for (let i = 0; i <= 10; i++) {
const x = i*60;
ctx.moveTo(x, 0);
ctx.lineTo(x, canvas.height);
ctx.stroke();
const y = i*60;
ctx.moveTo(0, y);
ctx.lineTo(canvas.width, y);
ctx.stroke();
}
//draw images
const p = ctx.lineWidth / 2; //padding
for (let xCell = 0; xCell < 10; xCell++) {
for (let yCell = 0; yCell < 10; yCell++) {
const x = xCell * 60;
const y = yCell * 60;
const img = new Image();
img.onload = function() {
ctx.drawImage(img, x+p, y+p, 60-p*2, 60-p*2);
};
//TODO: set img.src to your api url instead of the dummyimage url.
img.src = `https://dummyimage.com/60x60/000/fff&text=${xCell},${yCell}`;
}
}
};
Working example:
https://codepen.io/rockysims/pen/dLZgBm

Related

Why is my js to create raining bowties not working?

I am making a project where I need to make an html canvas with raining bowtie images. Here is my js:
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
let img = new Image("images.png")
var ok2animate = true;
img.onload = function(){
function Drop() {
this.x = Math.random() * (canvas.width - 20);
this.y = -Math.random() * 20;
this.fallRate = Math.random()*.5+.5;
}
//
Drop.prototype.draw = function () {
// this.x;
// this.y;
ctx.drawImage(img, this.x, this.y)
return (this);
}
//
Drop.prototype.fall = function () {
this.y += this.fallRate;
return (this);
}
function animate() {
// request another animation frame
if (ok2animate) {
requestAnimationFrame(animate);
}
ctx.fillRect(0,0,canvas.width,canvas.height)
//ctx.clearRect(0, 0, canvas.width, canvas.height);
// make all drops fall and then redraw them
for (var i = 0; i < drops.length; i++) {
drops[i].fall().draw();
}
}
// an array of objects each representing 1 drop
var drops = [];
// add some test drops
for (var i = 0; i < 10; i++) {
drops.push(new Drop());
}
setInterval(function(){requestAnimationFrame(animate)}, 1000)
requestAnimationFrame(animate)
}
<canvas id="canvas" width=300 height=300></canvas>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
How do I make it so the images rain down at 1 second intervals?
(I have included the image file in the same folder)
I have tried using an image file from the web, using a bigger canvas, uwing other versions of jquery, but none of those worked.
Image creation
You can create a new image with the Image constructor. You already did that, however, the arguments that the constructor accepts are the width and the height of the image, not the url. You need the src property of the image to reference the image file.
And since you only use 1 single image, that isn't changing, you only have to create and load it once. You can reuse the same image for as many times as you want.
Starting the loop
Now, you need to start the loop after all the images (which in this case is one) has been loaded. Listen for the onload event on the image and call the setInterval function whenever the image is loaded.
setInterval will start of the rendering here, so there is no need to call requestAnimationFrame(animate) anywhere else.
const canvas = document.getElementById("canvas");
const ctx = canvas.getContext("2d");
// Create the image like this.
const image = new Image(100, 100);
image.src = "https://www.fillmurray.com/100/100";
function Drop() {
this.x = Math.random() * (canvas.width - 20);
this.y = -Math.random() * 20;
this.fallRate = Math.random() * 10 + 0.5;
}
Drop.prototype.draw = function() {
ctx.drawImage(image, this.x, this.y)
return this;
}
Drop.prototype.fall = function() {
this.y += this.fallRate;
return this;
}
const drops = [];
for (let i = 0; i < 10; i++) {
drops.push(new Drop());
}
function animate() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.fillRect(0, 0, canvas.width, canvas.height)
for (const drop of drops) {
drop.fall().draw();
}
}
image.onload = () => {
setInterval(function() {
requestAnimationFrame(animate)
}, 1000)
};
<canvas id="canvas" width=300 height=300></canvas>

HTML5 Canvas blocked after window resize

What I'm trying to accomplish is simply to redraw some stuff on my canvas after it's resized. My problem is that after the canvas resizes, nothing seems to appearing on it. I tried to put some simple code for drawing a rectangle inside the resizing handler as well, and what I noticed is that the rectangle appears during the window resizing and afterwards the canvas is left blank. Below is my code.
var canvass = document.getElementById('zipper-canvas');
var ctx = canvass.getContext('2d');
var repetitions;
var firstRowX = 0; var firstRowY ;
var secondRowX = 5; var secondRowY ;
$(function() {
canvass.width = window.innerWidth;
repetitions = canvass.width / 10;
canvass.height = 30;
ctx = canvass.getContext('2d');
firstRowY = canvass.height / 2 - 3;
secondRowY = canvass.height / 2 + 1;
redraw();
//resize the canvass to fill browser window dynamically
window.addEventListener('resize', resizecanvass, false);
//for some reason i cannot draw on the canvas after it was resized
function resizecanvass() {
canvass.width = window.innerWidth;
repetitions = canvass.width / 10;
canvass.height = 30;
ctx = canvass.getContext('2d');
firstRowY = canvass.height / 2 - 3;
secondRowY = canvass.height / 2 + 1;
/**
* Your drawings need to be inside this function otherwise they will be reset when
* you resize the browser window and the canvass goes will be cleared.
*/
redraw();
}
function redraw() {
canvass = document.getElementById("zipper-canvas");
ctx = canvass.getContext('2d');
ctx.clearRect(0, 0, canvass.width, canvass.height);
console.log(repetitions);
for (var r = 0; r < repetitions; r++) {
ctx.beginPath();
ctx.rect(firstRowX, firstRowY, 5, 5);
ctx.fillStyle = "#edeeef";
ctx.fill();
ctx.closePath();
firstRowX = firstRowX + 10;
}
for (var r2 = 0; r2 < repetitions; r2++) {
ctx.beginPath();
ctx.rect(secondRowX, secondRowY, 5, 5);
ctx.fillStyle = "#a2a3a5";
ctx.fill();
ctx.closePath();
secondRowX = secondRowX + 10;
}
}
});
The problem is that you don't reset your firstRowX and secondRowX variables, so you end up drawing outside the canvas. I fixed that and also moved variable definitions where they belong.
var canvass = document.getElementById('zipper-canvas');
// Could be const
var firstRowX = 0;
var secondRowX = 5;
// Set the correct size on load
resizecanvass();
//resize the canvass to fill browser window dynamically
window.addEventListener('resize', resizecanvass, false);
//for some reason i cannot draw on the canvas after it was resized
function resizecanvass() {
canvass.width = window.innerWidth;
canvass.height = 30;
/**
* Your drawings need to be inside this function otherwise they will be reset when
* you resize the browser window and the canvass goes will be cleared.
*/
redraw();
}
function redraw() {
var ctx = canvass.getContext('2d');
ctx.clearRect(0, 0, canvass.width, canvass.height);
var repetitions = canvass.width / 10;
var firstRowY = canvass.height / 2 - 3;
var secondRowY = canvass.height / 2 + 1;
for (var r = 0; r < repetitions; r++) {
ctx.beginPath();
ctx.rect(firstRowX + r*10, firstRowY, 5, 5);
ctx.fillStyle = "#edeeef";
ctx.fill();
ctx.closePath();
}
for (var r2 = 0; r2 < repetitions; r2++) {
ctx.beginPath();
ctx.rect(secondRowX + r2*10, secondRowY, 5, 5);
ctx.fillStyle = "#a2a3a5";
ctx.fill();
ctx.closePath();
}
}
canvas {
outline:1px solid black;
}
body, html, canvas {
margin: 0px;padding:0px;
}
<canvas id='zipper-canvas'></canvas>
Here's a JSFiddle where you can test the resizing behavior:
https://jsfiddle.net/Darker/noxd4x64/1/
Note that the same effect could be achieved using CSS background without any programming.

How do I add four rotating images to an animated background?

I am trying to add four rotating images to an animated background.
I can only get one image working correctly with my code below.
How can I add in the other three images?
var canvas = document.getElementById('c');
var ctx = canvas.getContext('2d');
var img = document.createElement('img');
img.onload = function(){
render();
}
img.src = 'nano3.png';
function drawImage(img,x,y,r,sx,sy){
sx=sx||0;
sy=sy||0;
r=(r*Math.PI/180)||0;
var cr = Math.cos(r);
var sr = Math.sin(r);
ctx.setTransform(cr,sr,-sr,cr,x-(cr*sx-sr*sy),y-(sr*sx+cr*sy));
ctx.drawImage(img,1,2);
}
var r = 1;
function render(){
requestAnimationFrame(render);
ctx.setTransform(1, 0, 0, 1, 0, 0);
ctx.clearRect(0,0,800,800);
drawImage(img,50,50,r++,img.width/2,img.height/2);
}
This should help you out, I just created an object known as rotatingimage which stores a location, an image and its current rotation. We call the 'draw' method in a 'setInterval' function call which deals with rotating the canvas and then drawing the sprite correctly.
Just a note rotating many images can cause the canvas to lag also the CurrentRotation variable never gets reset to 0 when it reaches >359 so the CurrentRotation variable will keep going higher and higher, you may want to fix that in the RotatingImage.prototype.Draw function
jsFiddle:https://jsfiddle.net/xd8brfrk/
Javascript
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
function RotatingImage(x, y, spriteUrl, rotationSpeed) {
this.XPos = x;
this.YPos = y;
this.Sprite = new Image();
this.Sprite.src = spriteUrl;
this.RotationSpeed = rotationSpeed;
this.CurrentRotation = 0;
}
RotatingImage.prototype.Draw = function(ctx) {
ctx.save();
this.CurrentRotation += 0.1;
ctx.translate(this.XPos + this.Sprite.width/2, this.YPos + this.Sprite.height/2);
ctx.rotate(this.CurrentRotation);
ctx.translate(-this.XPos - this.Sprite.width/2, -this.YPos - this.Sprite.height/2);
ctx.drawImage(this.Sprite, this.XPos, this.YPos);
ctx.restore();
}
var RotatingImages = [];
RotatingImages.push(new RotatingImage(50, 75, "http://static.tumblr.com/105a5af01fc60eb94ead3c9b342ae8dc/rv2cznl/Yd9oe4j3x/tumblr_static_e9ww0ckmmuoso0g4wo4okosgk.png", 1));
RotatingImages.push(new RotatingImage(270, 25, "http://static.tumblr.com/105a5af01fc60eb94ead3c9b342ae8dc/rv2cznl/Yd9oe4j3x/tumblr_static_e9ww0ckmmuoso0g4wo4okosgk.png", 1));
RotatingImages.push(new RotatingImage(190, 180, "http://static.tumblr.com/105a5af01fc60eb94ead3c9b342ae8dc/rv2cznl/Yd9oe4j3x/tumblr_static_e9ww0ckmmuoso0g4wo4okosgk.png", 1));
RotatingImages.push(new RotatingImage(100, 270, "http://static.tumblr.com/105a5af01fc60eb94ead3c9b342ae8dc/rv2cznl/Yd9oe4j3x/tumblr_static_e9ww0ckmmuoso0g4wo4okosgk.png", 1));
setInterval(function() {
ctx.fillStyle = "#000"
ctx.fillRect(0, 0, canvas.width, canvas.height);
for (var i = 0; i < RotatingImage.length; i++) {
var rotatingImage = RotatingImages[i];
rotatingImage.Draw(ctx);
}
}, (1000 / 60));
you can use save and restore to apply different transform to your drawing
https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/save
https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/restore

Picture background for canvas particle

I'm trying to create background for every created particle.
Canvas pattern is not working properly. I'm getting this error >> "SyntaxError: An invalid or illegal string was specified"
HTML
<canvas id="canvas"></canvas>
JS
(function(){
window.onload = function(){
var canvas = document.getElementById('canvas');
var ctx = canvas.getContext('2d'),
particles = {},
particleIndex = 0,
particleNum = 1;
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
ctx.fillStyle = '#000';
ctx.fillRect(0, 0, canvas.width, canvas.width);
function Particle(){
this.x = canvas.width / 2;
this.y = 0;
this.vx = Math.random() * 10 - 5;
this.vy = Math.random() * 10 - 5;
this.gravity = 0.2;
particleIndex++;
particles[particleIndex] = this;
this.id = particleIndex;
this.test = 0;
this.maxLife = 100;
}
Particle.prototype.draw = function(){
this.x += this.vx;
this.y += this.vy;
this.vy += this.gravity;
this.test++;
if ( this.test >= this.maxLife ) {
delete particles[this.id];
};
var img = new Image();
img.src = 'img/aaa.png';
var pattern = ctx.createPattern(img,'repeat');
ctx.fillStyle = pattern;
ctx.fillRect(this.x, this.y, 20, 20);
};
setInterval(function(){
ctx.fillStyle = "#000";
ctx.fillRect(0, 0, canvas.width, canvas.height);
for (var i = 0; i < particleNum; i++) {
new Particle();
};
for(var i in particles) {
particles[i].draw();
}
},30)
}})();
I was trying to do this also with ctx.drawImage(), but picture was displayed one time only.
Any tips?:)
Fiddle
I think the issue is the image being loaded later than its used.
Inside your draw() you have:
var img = new Image();
img.src = 'img/aaa.png';
var pattern = ctx.createPattern(img,20,20);
It is a bad idea to create new images everytime you want to draw. I strongly suggest you create the img variable outside of the draw loop. Once you set the .src of an image, you have to wait until it is loaded to use it. There is an onload event you can use to let you know when its ready.
Here is an example:
var imgLoaded = false;
var img = new Image();
img.src = 'img/aaa.png';
img.onload = function() { imgLoaded = true; };
function draw() {
...
if (imgLoaded) {
var pattern = ctx.createPattern(img, 'repeat');
...
}
...
}

draw on image using canvas

I have a picture which which is loaded like this:
<img src="map/racetrack.jpg" id="map">
And here is my drawing function:
this.drawRoute = function(){
var pos = [];
var canvas = $('<canvas/>')[0];
var img = $('#map')[0];
var ctx = canvas.getContext("2d");
canvas.width = img.width;
canvas.height = img.height;
$(window).on('mousedown', function(e){
pos.push({
x: e.clientX,
y: e.clientY
});
});
if (positions.length > 1) {
ctx.beginPath();
ctx.moveTo(pos[0].x, pos[0].y);
for (var i = 1; i < pos.length; i++) {
ctx.lineTo(pos[i].x, pos[i].y);
}
ctx.stroke();
}
}
But nothing is drawn on the picture. I can't see where the mistake is. I know usually I'm supposed to use <canvas> element, but I only need this particular part done in canvas, nothing else.
Here's the fiddle
Well a few things first you have no canvas element. Secondly I didnt see where you were calling the draw portion.
Live Demo
What I ended up doing was adding a canvas element, hiding the image, and then every time you draw it draws the image to the canvas, and then draws the points over it. This should hopefully be enough to get you started.
var pos = [];
var canvas = $('#canvas')[0];
var img = $('#map')[0];
var ctx = canvas.getContext("2d");
canvas.width = img.width;
canvas.height = img.height;
function render() {
ctx.drawImage(img, 0, 0);
if (pos.length > 1) {
ctx.beginPath();
ctx.moveTo(pos[0].x, pos[0].y);
for (var i = 1; i < pos.length; i++) {
ctx.lineTo(pos[i].x, pos[i].y);
}
ctx.stroke();
}
}
$(window).on('mousedown', function (e) {
pos.push({
x: e.clientX,
y: e.clientY
});
render();
});
render();

Categories

Resources