I am new to javascript and am trying to make an animation of snow for an assignment.
So far I have been able to create some small background snow (randomly sized circles) but I want to use some snowflake png files for more moving snow. This is what I have but I am pretty sure the image parts are pretty wrong.
Really not sure how to make this work so any tips would be greatly appreciated.
var canvas = document.getElementById("canvas");
var context = canvas.getContext("2d");
var colours = ["white", "azure", "floralwhite", "#EAEDED"];
var r = 3.5;
var snow = [];
for (var i=0;i<1000;i++){
var s = {
x : i*2,
y : 0,
colour : colours[Math.round(Math.random()*colours.length)],
dx : Math.random(),
dy : Math.random()*3,
}
snow.push(s);
}
var flakes = ["flak1", "flak2", "flak3"];
flak1 = new Image();
flak1.src = "snow1.png";
flak2 = new Image();
flak2.src = "snow2.png";
flak3 = new Image();
flak3.src = "snow3.png";
for (var e=0;e<10;e++){
var f = {
x: e*2,
y: 0,
image: flakes[Math.round(Math.random()*flakes.length)],
dx: Math.random(),
dy: 1,
}
flakes.push(f);
}
var grd = context.createLinearGradient(0,0,0,500);
grd.addColorStop(0, "#85C1E9");
grd.addColorStop(1, "#EBF5FB");
function itSnows(){
//draw background
context.fillStyle = grd;
context.fillRect(0,0,canvas.width,canvas.height);
context.fillStyle = "white";
context.fillRect(0,650,canvas.width,50);
house = new Image();
house.src = "house.png";
context.drawImage(house, 10, 490,200,200);
context.drawImage(house, 200, 490,300,200);
context.drawImage(house, 480, 490,250,200);
context.drawImage(house, 740, 490,200,200);
context.drawImage(house, 950, 490,250,200);
sun = new Image();
sun.src = "sun.png";
context.drawImage(sun,0,0,600,350);
//draw snow
for(var i=0;i<snow.length;i++){
context.fillStyle = snow[i].colour;
context.beginPath();
context.arc(snow[i].x,snow[i].y,r*Math.random(),0,2*Math.PI);
context.fill();
snow[i].y = (snow[i].y + snow[i].dy) % 700;
snow[i].x = (snow[i].x + snow[i].dx) % canvas.width;
//draw flakes
for (var e=0;e<flakes.length;e++){
context.drawImage(flakes[e], flakes[e].x, flakes[e].y, 30, 30);
flakes[e].y = (flakes[e].y + flakes[e].dy) % 700;
flakes[e].x = (flakes[e].x + flakes[e].dx) % canvas.width;
}
}
}
setInterval(itSnows, 25);
Related
Solved Had to render the images globally outside of the draw method. Here's a link to the github if you find this question and are wondering what the solution looks like in the full code. Its a bit too long to post here as an update. github canvas orbs
back to the original question:
I'm trying to render custom Class objects inside an HTML canvas. Doesn't work with class, but the the same data works without class.
Here's the code:
import './styles/index.css';
let canvas = document.getElementById("canvas");
let context = canvas.getContext("2d");
var window_height = window.innerHeight;
var window_width = window.innerWidth;
canvas.width = 500;
canvas.height = 400;
canvas.style.background = "#232a2e"
const convertSVG = (svgid) => {
const svg = document.getElementById(svgid);
const xml = new XMLSerializer().serializeToString(svg);
const svg64 = btoa(xml);
const b64Start = 'data:image/svg+xml;base64, ';
return b64Start + svg64;
}
class Orb {
constructor(xpos, ypos, radius, speed, image) {
this.xpos = xpos;
this.ypos = ypos;
this.radius = radius;
this.speed = speed;
this.image = convertSVG(image);
}
draw(context) {
const img = new Image();
img.onload = function() {
context.save();
context.beginPath();
context.arc(this.xpos, this.ypos, this.radius, 0, Math.PI * 2, false);
context.clip();
context.drawImage(img, (this.xpos - this.radius), (this.ypos - this.radius), 64, 64);
context.restore();
}
img.src = this.image;
}
}
const myOrb = new Orb(150, 150, 30, 1, 'javascript-icon');
myOrb.draw(context);
console.log(myOrb);
const img = new Image();
img.onload = function() {
context.save();
context.beginPath();
context.arc(300, 300, 30, 0, Math.PI * 2, false);
context.clip();
context.drawImage(img, (300-32), (300-32), 64, 64);
context.restore();
}
img.src = convertSVG('javascript-icon');
Currently it's only displaying the object I draw explicitly at the bottom of the code, and not the object of class Orb.
Here's a screen cap of the canvas:
current canvas render
EDIT: Additionally, I can generate a class object and draw the orb based on that. Like so:
const myOrb = new Orb(300, 300, 30, 1, 'javascript-icon');
const myOrb2 = new Orb(150, 150, 30, 1, 'java-icon');
const img = new Image();
img.onload = function() {
context.save();
context.beginPath();
context.arc(myOrb.xpos, myOrb.ypos, myOrb.radius, 0, Math.PI * 2, false);
context.clip();
context.drawImage(img, (myOrb.xpos-myOrb.radius-2), (myOrb.ypos-myOrb.radius-2), 64, 64);
context.restore();
}
img.src = myOrb.imageSRC;
console.log(myOrb);
console.log(myOrb2);
myOrb2.draw(context);
myOrb renders, but myOrb2 which is drawn with the method of the class is not rendered.
Here's an approach to take. Load the images globally and call draw when image is loaded.
let canvas = document.getElementById("canvas");
let context = canvas.getContext("2d");
var window_height = window.innerHeight;
var window_width = window.innerWidth;
canvas.width = 500;
canvas.height = 400;
canvas.style.background = "#232a2e"
const img1 = new Image();
img1.src = 'https://cdn.iconscout.com/icon/free/png-256/javascript-2752148-2284965.png';
const img2 = new Image();
img2.src = 'https://iconape.com/wp-content/png_logo_vector/cib-javascript.png'
class Orb {
constructor(xpos, ypos, radius, speed, image) {
this.xpos = xpos;
this.ypos = ypos;
this.radius = radius;
this.speed = speed;
this.image = image;
}
draw(context) {
context.save();
context.beginPath();
context.arc(this.xpos, this.ypos, this.radius, 0, Math.PI * 2, false);
context.clip();
context.drawImage(this.image, (this.xpos - this.radius), (this.ypos - this.radius), 64, 64);
context.restore();
}
}
const myOrb = new Orb(150, 150, 30, 1, img1);
const myOrb2 = new Orb(350, 150, 30, 1, img2);
window.onload = function() {
myOrb.draw(context);
myOrb2.draw(context);
}
<canvas id="canvas"></canvas>
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!
In my code:
var canvas = document.createElement('canvas');
canvas.width = 1600;
canvas.height = 900;
document.body.appendChild(canvas);
var similarX = 0;
var similarY = 0;
document.addEventListener('mousemove',function(event){
similarX = event.clientX;
similarY = event.clientY;
document.getElementById('body').innerHTML = "x:" + similarX + ", y:" + similarY +", imgData:" + pixelData;
var pixelData = rect.getImageData(60, 60, 1, 1).data;
})
window.addEventListener('load' , start);
var c = canvas.getContext('2d')
var rect = canvas.getContext ('2d')
var circle = canvas.getContext ('2d')
function start() {
c.clearRect(0, 0, 1600, 900);
c.fillStyle = 'green' ;
c.fillRect(similarX - 12, similarY - 50, 20, 20);
rect.fillStyle = 'black';
rect.fillRect(50,50,80,80);
window.requestAnimationFrame(start)
}
document.body.appendChild(canvas);
I want to detect what color are the pixels around the green player square so that if it touches the black box, it is detected by a getImageData() command? I tried reading the other posts, but I couldn't find a way to use them. Is there a solution that can easily be placed inside the code?
StackOverflow community, I'm fairly new to JavaScript programming and I'm having some issues with the HTML5/JavaScript Canvas Combo.
The idea is to, following the click of a button, to verify some lines and, then, show on the screen the image (pre-defined) with some text in specific coordinates, the text depends on the input value, as they are stored in an Array.
The thing is, I'm not being able to draw the text on the Image, only the Image appears. The code goes as follows:
Globally Defined:
...
canvas = document.getElementById("cvs"),
ctx = canvas.getContext('2d'),
...
The Draw() function:
function draw() {
if (img_is_loaded) {
img = document.getElementById("background-A");
var maxh = 600,
maxw = 900,
height = img.height,
width = img.width,
name_input = name[0],
note_input = note[0],
date_input = date[0],
sur_input = sur[0];
while (height > maxh || width > maxw) {
--height;
--width;
}
canvas.height = height;
canvas.width = width;
ctx.save();
ctx.clearRect(0, 0, width, height);
ctx.drawImage(img, 0, 0, width, height);
ctx.font = "54px Times Roman";
ctx.fillStyle = "#000000";
ctx.fillText = (name_input, 35, 320);
ctx.font = "21px Times Roman";
ctx.fillStyle = "#000000";
ctx.fillText = (note_input, 61, 432);
ctx.fillText = (date_input, 254, 501);
ctx.fillText = (sur_input, 254, 528);
}
} else {
setTimeout(draw, 100);
}
}
I'm getting the Image, but no text. I'm aware that the issue, normally, is that I need to draw them "at the same time", so I tried:
function draw() {
if (img_is_loaded) {
var imageObj = new Image();
imageObj.onload = function(){
var maxh = 600,
maxw = 900,
height = imageObj.height,
width = imageObj.width,
name_input = name[0],
note_input = note[0],
date_input = date[0],
sur_input = sur[0];
while (height > maxh || width > maxw) {
--height;
--width;
}
canvas.height = height;
canvas.width = width;
ctx.save();
ctx.clearRect(0, 0, width, height);
$('#spinner-generate').hide();
ctx.drawImage(imageObj, 0, 0, width, height);
ctx.font = "54px Times Roman";
ctx.fillStyle = "#000000";
ctx.fillText = (name_input, 35, 320);
ctx.font = "21px Times Roman";
ctx.fillStyle = "#000000";
ctx.fillText = (note_input, 61, 432);
ctx.fillText = (date_input, 254, 501);
ctx.fillText = (sur_input, 254, 528);
ctx.restore();
}
imageObj.src = "IMAGEPATH";
} else {
setTimeout(draw, 100);
}
}
But, in this case, the "imageObj.onload" function gets skipped by the code, that automatically jumps to "else".
I'm really confused at this point, since every source I consulted says that it is "simple" and uses the imageObj.onload example, but with the "window.onload" combination.
Is there something I'm missing regarding the Canvas' "Order of things"?
I appreciate and thank in advance for any response or input.
You're using fillText as a property while it should have been used as a method - simply change the lines to this format:
ctx.fillText(name_input, 35, 320);
I did not check the rest of the code.
The problem I have is on the image slider. The blue triangule is created using a multiply canvas effect seen here:
http://albertogasparin.it/articles/2011/05/html5-multiply-filter-canvas/
I want the blue triangle to have it's opacity to 0.5, but if I put that on the css (canvas element) it also affects the opacity of the image that's below. Any ideas how to achieve this?
This is my code:
function to_canvas(im,w,h){
var isIE8 = $.browser.msie && +$.browser.version === 8;
var canvas;
var imageBottom;
var im_w = w;
var im_h = h;
var imgData;
var pix;
var pixcount = 0;
var paintrow = 0;
var multiplyColor = [70, 116, 145];
var x_offset = Math.floor(($('#'+im).attr('width') - im_w)/2);
var y_offset = Math.floor(($('#'+im).attr('height') - im_h)/2);
if ( isIE8 ) {
$('<div />' , {
'id' : 'div-'+im,
'class' : 'pseudo_canvas'
}).css({
'width' : im_w,
'height' : im_h
}).insertBefore('#'+im);
$('#'+im).appendTo('#div-'+im).fadeIn();
$('<img>' , {
'src' : '/img/blueborder.png',
'class' : 'blueborder'
}).css({
}).insertBefore('#'+im);
$('#'+im).appendTo('#div-'+im).fadeIn();
}else{
imageBottom = document.getElementById(im);
canvas = document.createElement('canvas');
canvas.width = im_w;
canvas.height = im_h;
imageBottom.parentNode.insertBefore(canvas, imageBottom);
ctx = canvas.getContext('2d');
ctx.drawImage(imageBottom, -x_offset , -y_offset);
imgData = ctx.getImageData(0, 0, canvas.width, canvas.height);
pix = imgData.data;
for (var i = 0 ; i < pix.length; i += 4) {
if(pixcount > im_w - (im_h - paintrow) ){
pix[i ] = multiply(multiplyColor[0], pix[i ]);
pix[i+1] = multiply(multiplyColor[1], pix[i+1]);
pix[i+2] = multiply(multiplyColor[2], pix[i+2]);
}
if(pixcount < im_w-1){
pixcount++;
}else{
paintrow++;
pixcount = 0;
}
}
ctx.putImageData(imgData, 0, 0);
/* $('#'+im).remove(); */
}
}
function multiply(topValue, bottomValue){
return topValue * bottomValue / 255;
}
This is how I want the triangle color/opacity (obviously without the opacity of the image on the back):
if u have canvas-
var canvas = document.getElementById("canvas");
var context = canvas.getContext("2d");
context.globalCompositeOperation = "destination-over";
context.fillStyle = "rgba(0, 0, 200, 0.5)";//Change the color combination here
context.fillRect(0, 0, 1000, 1000);
one way would be to use a semi-transparent background instead (e.g. png file)