I am trying to draw and move an image using JS.
This code works up until the moveImage function which simply does nothing. Can anyone help me figure this out?
I believe that I can get the image to move if I place it in the html, but I would prefer to have the script code place it instead if possible.
function init() {
var x = 1, y = 1;
var context = document.getElementById("Vehicle").getContext("2d");
var img = new Image();
img.onload = function () { context.drawImage(img, x, y, 24, 20); }
img.src = "images/Image.png";
//move
function moveImage(imgX, imgY) {
img.style.left = imgX + "px";
img.style.top = imgY + 'px';
}
setInterval(function () {
var FPS = 60;
x++;
y++;
if (x > 1000) { x = 1; }
if (y > 1000) { y = 1; }
moveImage(x, y);
}, 1000/FPS);
};
My guess is that img.style.left/right is either not correct or that I am not pointing to img properly.
If there is no way to do this, is there a way for me to remove (not just hide) the image so I can redraw it in the new location?
You have a scope issue. You are defining FPS inside the interval. This needs to be done before so that it can be used on the interval step parameter.
var FPS = 60;
var timer = (1000/FPS);
setInterval(function () {
x++;
y++;
if (x > 1000) { x = 1; }
if (y > 1000) { y = 1; }
moveImage(x, y);
}, timer);
Furthermore you cannot simply reposition an image on a canvas. It needs to be redrawn onto the canvas.
Once you call context.drawImage() the image can no longer be manipulated. You have, as it suggests, drew this onto the canvas. It's not the same as a HTML element within the DOM. It is now simply coloured pixels on a canvas.
See Demo: http://jsfiddle.net/8Ljvnt8j/1/
However you'll notice that the image is being repeated. This is because you are drawing on top of canvas. The canvas is 2d so you are simply painting on top of what is already there.
Therefore you need to clear down the canvas.
img.onload = function () {
context.clearRect(0, 0, canvas.width, canvas.height);
context.drawImage(img, imgX, imgY, 24, 20);
}
See Demo: http://jsfiddle.net/8Ljvnt8j/2/
All in all:
function init() {
var x = 1;
var y = 1;
var canvas = document.getElementById("Vehicle");
drawImage();
//move
function drawImage() {
var context = document.getElementById("Vehicle").getContext("2d");
var img = new Image();
img.onload = function () {
context.clearRect(0, 0, canvas.width, canvas.height);
context.drawImage(img, x, y, 24, 20);
}
img.src = "https://placeholdit.imgix.net/~text?txtsize=5&txt=20%C3%9720&w=20&h=20";
}
var FPS = 60;
var timer = (1000/FPS);
setInterval(function () {
x++;
y++;
if (x > 1000) { x = 1; }
if (y > 1000) { y = 1; }
drawImage();
}, timer);
};
init();
Related
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>
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
I made a simple game in HTML that basically draws a sprite inside a canvas box and allows me to move it around via the arrow keys. But for some reason when I put boundaries on the sprite so that it won't leave the canvas, it didn't work out so well.
Here is an image of the sprite in the canvas (the canvas is the box in which the yellow sprite is inside of)
The sprite does have boundaries, at which it can't go further, but I wanted them to be AT the canvas lines. Right now it's constrained to some invisible box WITHIN the canvas. But nothing I see in the code is justifying my error. What am I doing wrong?
Here's the code:
// JavaScript Document
var canvasWidth = 800;
var canvasHeight = 600;
$('#gameCanvas').attr('width', canvasWidth);
$('#gameCanvas').attr('height', canvasHeight);
var keysDown = {};
$('body').bind('keydown', function(e){
keysDown[e.which] = true;
});
$('body').bind('keyup', function(e){
keysDown[e.which] = false;
});
var canvas = $('#gameCanvas')[0].getContext('2d');
var FPS = 30;
var image = new Image();
image.src = "ship.png";
var playerX = (canvasWidth/2) - (image.width/2);
var playerY = (canvasHeight/2) - (image.height/2);
setInterval(function() {
update();
draw();
}, 1000/FPS);
function update(){
if(keysDown[37]){
playerX -= 10;
}
if(keysDown[38]){
playerY -= 10;
}
if(keysDown[39]){
playerX += 10;
}
if(keysDown[40]){
playerY += 10;
}
playerX = clamp(playerX, 0, canvasWidth - image.width);
playerY = clamp(playerY, 0, canvasHeight - image.height);
}
function draw() {
canvas.clearRect(0,0, canvasWidth, canvasHeight);
canvas.strokeRect(0, 0, canvasWidth, canvasHeight);
canvas.drawImage(image, playerX, playerY);
}
function clamp(x, min, max){
return x < min ? min : (x > max ? max : x);
}
A bit confused by the perceived error so here is a crack at it.
Live Demo
What I did was added a load event listener for the image to make sure its fully loaded before starting the update,
image.addEventListener('load', function () {
update();
});
Notice I just call update, and your update function calls draw, then the end of draw() calls requestAnimationFrame(update)
Always use requestAnimationFrame to do animations rather than intervals. You should notice it acting much smoother now.
I also added a bounding box around the image so you can see the boundaries. However if your issue is you want the image itself to go up against the borders of the canvas you just need to crop your image resource.
You can also do that with drawImage
Live Demo Cropped
Just use all 9 parameters of drawImage like so
drawImage(image, sourceX, sourceY, sourceWidth, sourceHeight,
destX, destY, destWidth, destHeight)
so to crop it you could do
var cropX = 80,
cropY = 20;
canvas.drawImage(image,
cropX, cropY, image.width-cropX, image.height-cropY,
playerX, playerY,image.width-cropX,image.height-cropY);
And it will draw the cropped image instead now.
One more suggestion is not to use jQuery for this, you don't need it you can select your canvas element without it using getElementById or querySelectorAll you can also bind your events using addEventListener
Code in its entirety.
// JavaScript Document
var canvasWidth = 800;
var canvasHeight = 600;
$('#gameCanvas').attr('width', canvasWidth);
$('#gameCanvas').attr('height', canvasHeight);
var keysDown = {};
$('body').bind('keydown', function (e) {
keysDown[e.which] = true;
});
$('body').bind('keyup', function (e) {
keysDown[e.which] = false;
});
var canvas = $('#gameCanvas')[0].getContext('2d');
var FPS = 30;
var image = new Image();
image.crossOrigin = "Anonymous";
image.src = "http://i.imgur.com/LfcwdP7.gif";
image.addEventListener('load', function () {
update();
});
var playerX = (canvasWidth / 2) - (image.width / 2);
var playerY = (canvasHeight / 2) - (image.height / 2);
function update() {
if (keysDown[37]) {
playerX -= 10;
}
if (keysDown[38]) {
playerY -= 10;
}
if (keysDown[39]) {
playerX += 10;
}
if (keysDown[40]) {
playerY += 10;
}
playerX = clamp(playerX, 0, canvasWidth - image.width);
playerY = clamp(playerY, 0, canvasHeight - image.height);
draw();
}
function draw() {
canvas.clearRect(0, 0, canvasWidth, canvasHeight);
canvas.strokeRect(0, 0, canvasWidth, canvasHeight);
canvas.strokeRect(playerX, playerY, image.width, image.height);
canvas.drawImage(image, playerX, playerY);
requestAnimationFrame(update);
}
function clamp(x, min, max) {
return x < min ? min : (x > max ? max : x);
}
Your code is working perfectly. The image IS touching the boundaries and doesn't go beyond. Maybe I didn't understand your problem, so please comment to clarify what you need.
The demo on jsfiddle below:
http://jsfiddle.net/8x5yv233/
Note: I think you need to wait for picture to load, before doing anything. Something like that:
var image = new Image();
image.onload = function () {
setInterval(function () {
update();
draw();
}, 1000/FPS);
}
image.src = 'yourpic.png';
I know that there are many similiar questions already asked on stackoverflow, but still, I can not figure out how to do it. I want to rotate only ball texture. draw is called with timer:
var canvas;
var ctx;
var width;
var height;
var ready;
var textures;
var loadIndex;
var loadCount;
var keyCodes;
var mouseLoc;
var playerX;
var playerY;
var playerVelocity;
function init() {
canvas = document.getElementById('game');
ctx = canvas.getContext("2d");
width = canvas.width;
height = canvas.height;
textures = [];
loadingCount = 0;
keyCodes = [];
mouseLoc = {};
playerX = 0;
playerY = 0;
playerVelocity = 6;
textures['Background'] = loadTexture('./textures/Background.png');
textures['Ball'] = loadTexture('./textures/Ball.png');
setInterval(function(){
if(loadingCount == 0) {
update();
draw();
}
}, 50);
}
function update(){
if(keyCodes[37])
playerX -= playerVelocity;
if(keyCodes[38])
playerY -= playerVelocity;
if(keyCodes[39])
playerX += playerVelocity;
if(keyCodes[40])
playerY += playerVelocity;
}
function draw() {
//ctx.clearRect(0, 0, width, height);
//ctx.beginPath();
drawBackground();
drawPlayer();
//ctx.closePath();
//ctx.fill();
}
function drawBackground(){
ctx.drawImage(textures['Background'], 0, 0, width, height);
}
function drawPlayer(){
ctx.save();
ctx.rotate(0.17);
ctx.drawImage(textures['Ball'], playerX, playerY, 100, 100);
ctx.restore();
}
function loadTexture(src){
var image = new Image();
image.src = src;
loadingCount++;
image.onload = function(){
loadingCount--;
};
return image;
}
document.onkeydown = function(evt){
keyCodes[evt.keyCode] = true;
evt.returnValue = false;
}
document.onkeyup = function(evt){
keyCodes[evt.keyCode] = false;
}
document.onmousemove = function(evt){
mouseLoc.x = evt.layerX;
mouseLoc.y = evt.layerY;
}
document.onmousedown = function(evt){
mouseLoc.down = true;
}
document.onmouseup = function(evt){
mouseLoc.down = false;
}
init();
Assuming that you want to give the illusion of the ball continuing to rotate, you should increase the rotation angle for each frame drawn.
As written, your code will give the ball a fixed rotation of 0.17 radians on each frame.
var frame = 0;
function drawPlayer() {
ctx.save();
ctx.rotate(0.17 * frame);
...
ctx.restore();
}
function draw() {
++frame;
drawPlayer();
...
}
You just need to save and restore the state of the canvas('s state-machine)
function drawPlayer(){
ctx.save();
ctx.rotate(0.17);
ctx.drawImage(textures['Ball'], playerX, playerY, 100, 100);
ctx.restore();
}
You want to use delta time for calculating the distance of your rotation. That is, the time that has passed since the last frame. That will make your rotation smoother should your browser hiccup and lose a frame here or there.
So store the time of each frame so you can make the comparison between frames and set your rotation speed as radians per second.
I am trying to fade an image in a canvas environment. Essientially what I want to do is while moving an image from left to right, I want to fade it from 0% alpha to 100% alpha. When I comment the globalAlpha and alpha info out in my code, it moves like I want it to, my only issue is getting it to fade. I am able to get the globalAlpha function to work, but it affects all the artwork in the canvas area. Is there a way I can just affect the one element? eventually I will want to fade in multiple elements at different times in the animation based on a timer, but if I can get this to work first I can go from there.
window.addEventListener('load', eventWindowLoaded, false);
function eventWindowLoaded()
{
canvasApp();
}
function canvasSupport ()
{
return Modernizr.canvas;
}
function canvasApp()
{
if (!canvasSupport())
{
return;
}
var pointImage = new Image();
pointImage.src = "images/barry.png";
var barry = new Image();
barry.src = "images/barry.png";
/*var alpha = 0;
context.globalAlpha = 1;*/
function drawScreen()
{
//context.globalAlpha = 1;
context.fillStyle = '#EEEEEE';
context.fillRect(0, 0, theCanvas.width, theCanvas.height);
//context.globalAlpha = alpha;
//Box
context.strokeStyle = '#000000';
context.strokeRect(1, 1, theCanvas.width-2, theCanvas.height-2);
if (moves > 0 )
{
moves--;
ball.x += xunits;
ball.y += yunits;
}
context.drawImage(barry, ball.x, ball.y);
/*context.restore();
alpha += .1;
if (alpha > 1)
{
alpha = 0;
}*/
}
var speed = 1;
var p1 = {x:20,y:250};
var p2 = {x:40,y:250};
var dx = p2.x - p1.x;
var dy = p2.y - p1.y;
var distance = Math.sqrt(dx*dx + dy*dy);
var moves = distance/speed;
var xunits = (p2.x - p1.x)/moves;
var yunits = (p2.y - p1.y)/moves;
var ball = {x:p1.x, y:p1.y};
var points = new Array();
theCanvas = document.getElementById("canvas");
context = theCanvas.getContext("2d");
ctx = theCanvas.getContext("2d");
setInterval(drawScreen, 10);
}
any suggestions are welcome!
I think this other question will give you a way to do so.
it shows how to load an element in the canvas context then how to fade it in..
How to change the opacity (alpha, transparency) of an element in a canvas element after it has been drawn?