I'm trying to get a single HTML with javascript to run a canvas with a snowfall effect that uses a custom image.
The canvas is working completely and is rendering the objects as white objects since the fill style is set to white. Instead of the white objects, I want to use a custom image, but somehow the script is not rendering the image in with the draw function.
I've tried changing the fillstyle to a pattern, but that doesn't seem to be available anymore?
Is there another option to fill the objects with a custom image?
Below is the code that I'm (Full HTML/Javascript code)
<html>
<head>
<meta charset=utf-8 />
<title>HTML5 Rain</title>
<!--[if IE]>
<script src="http://html5shiv.googlecode.com/svn/trunk/html5.js"></script>
<![endif]-->
<style>
article, aside, figure, footer, header, hgroup,
menu, nav, section { display: block; }
</style>
</head>
<body onload="init()">
<canvas id="canvasRain" width="1920px" height="1080px">Canvas Not Supported</canvas>
<script type="text/javascript">
var canvas = null;
var context = null;
var bufferCanvas = null;
var bufferCanvasCtx = null;
var pepperArray = [];
var pepperTimer = null;
var maxPeppers = 24; // Here you may set max peppers to be created
const pepperHeight = 85;
const pepperWidth = 121;
var pepperSrc = ['./img/T4c0_Pepper.png'];
var pepperImage = {};
var promiseArray = pepperSrc.map(function(imgurl){
var prom = new Promise(function(resolve,reject){
var img = new Image();
img.onload = function(){
pepperImage[imgurl] = img;
resolve();
};
img.src = imgurl;
});
return prom;
});
Promise.all(promiseArray).then(init);
function init() {
//Canvas on Page
canvas = document.getElementById('canvasRain');
context = canvas.getContext("2d");
//Buffer Canvas
bufferCanvas = document.createElement("canvas");
bufferCanvasCtx = bufferCanvas.getContext("2d");
bufferCanvasCtx.canvas.width = context.canvas.width;
bufferCanvasCtx.canvas.height = context.canvas.height;
pepperTimer = setInterval(addPepper, 200);
Draw();
setInterval(animate, 30);
}
function animate() {
Update();
Draw();
}
function addPepper() {
pepperArray[pepperArray.length] = new Pepper();
if (pepperArray.length == maxPeppers)
clearInterval(pepperTimer);
}
function blank() {
bufferCanvasCtx.fillStyle = "rgba(0,0,0,0.8)";
bufferCanvasCtx.fillRect(0, 0, bufferCanvasCtx.canvas.width, bufferCanvasCtx.canvas.height);
}
function Update() {
for (var i = 0; i < pepperArray.length; i++) {
if (pepperArray[i].y < context.canvas.height) {
pepperArray[i].y += pepperArray[i].speed;
if (pepperArray[i].y > context.canvas.height)
pepperArray[i].y = -5;
pepperArray[i].x += pepperArray[i].drift;
if (pepperArray[i].x > context.canvas.width)
pepperArray[i].x = 0;
}
}
}
function Pepper() {
this.x = Math.round(Math.random() * context.canvas.width);
this.y = -10;
this.drift = Math.random();
this.speed = Math.round(Math.random() * 5) + 6;
this.width = pepperWidth;
this.height = pepperHeight;
}
function Draw() {
context.save();
blank();
for (var i = 0; i < pepperArray.length; i++) {
bufferCanvasCtx.fillStyle = "white";
bufferCanvasCtx.fillRect(pepperArray[i].x, pepperArray[i].y, pepperArray[i].width, pepperArray[i].height);
}
context.drawImage(bufferCanvas, 0, 0, bufferCanvas.width, bufferCanvas.height);
context.restore();
}
</script>
</body>
Use the onload property to know when to fill.
var blueprint_background = new Image();
blueprint_background.src = 'https://your_image_source.com/image.png';
blueprint_background.onload = function(){
var pattern = context.createPattern(this, "repeat");
context.fillStyle = pattern;
context.rect(x,y,width,height);
context.fill();
};
Related
I want to resize the canvas field like paint app in javascript how can I do ?
My html file is :
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<link rel="stylesheet" type="text/css" href="paint.css">
<title>Paint</title>
</head>
<body>
<canvas id="canvas" style="border: solid 1px black">Your Browser does not support Canvas, please upgrade</canvas>
<script src="paint.js"></script>
</body>
</html>
Thanks !
It turned out to be a bit more complex.
Resizing the canvas clears it, therefore you need to do it this way:
create a new canvas
assign the dimensions
draw the old canvas over the new canvas
replace the old canvas with the new canvas
//Base canvas and dimensions
var canvas = document.body.appendChild(document.createElement("canvas"));
var width = canvas.height = canvas.width = 400;
var height = width;
var ctx = canvas.getContext("2d");
//Drawing variables
var lastPosition = null;
var drawing = false;
//Drawing functionality
function startDraw() {
drawing = true;
}
canvas.onmousedown = startDraw;
function stopDraw() {
drawing = false;
}
canvas.onmouseup = stopDraw;
canvas.onmouseleave = stopDraw;
function mouseMove(evt) {
var pos = {
x: evt.offsetX,
y: evt.offsetY
};
if (lastPosition !== null && drawing === true) {
ctx.beginPath();
ctx.moveTo(lastPosition.x, lastPosition.y);
ctx.lineTo(pos.x, pos.y);
ctx.closePath();
ctx.stroke();
}
lastPosition = pos;
}
canvas.onmousemove = mouseMove;
//Resizer functions
var resizerX = document.body.appendChild(document.createElement("button"));
resizerX.innerHTML = "Resize X";
resizerX.onclick = function() {
var newValue = null;
while (isNaN(newValue) || newValue < 10) {
newValue = parseInt(prompt("Insert new width", width.toString()));
}
var c = document.createElement("canvas");
width = newValue;
c.width = width;
c.height = height;
ctx = c.getContext("2d");
ctx.drawImage(canvas, 0, 0);
canvas.parentNode.replaceChild(c, canvas);
canvas = c;
canvas.onmousedown = startDraw;
canvas.onmouseup = stopDraw;
canvas.onmouseleave = stopDraw;
canvas.onmousemove = mouseMove;
};
var resizerY = document.body.appendChild(document.createElement("button"));
resizerY.innerHTML = "Resize Y";
resizerY.onclick = function() {
var newValue = null;
while (isNaN(newValue) || newValue < 10) {
newValue = parseInt(prompt("Insert new height", height.toString()));
}
var c = document.createElement("canvas");
height = newValue;
c.width = width;
c.height = height;
ctx = c.getContext("2d");
ctx.drawImage(canvas, 0, 0);
canvas.parentNode.replaceChild(c, canvas);
canvas = c;
canvas.onmousedown = startDraw;
canvas.onmouseup = stopDraw;
canvas.onmouseleave = stopDraw;
canvas.onmousemove = mouseMove;
};
canvas {
background-color: #eee
}
I want to load the sorted array images in canvas in a same sequence, for that i created a load function and I am calling it from there.
Every thing works fine, but the problem is that it does not draw the images on canvas at first call.
Here is a fiddle
With my current code, it does not show you an image , but when you run it again, it will create and show the canvas image.
I am facing the same issue in my local host where i load the images with ajax.
var ImagesArray = new Array("http://s4.postimg.org/dw8aujkkd/slim_Fit.png",
"http://s27.postimg.org/l6mq3hboz/outer_collar1.png",
"http://s22.postimg.org/e7alkm44x/inner_collar11.png",
"http://s12.postimg.org/h4kgdjn4t/maincolar.png",
"http://s13.postimg.org/edabwknfr/outer_fastening1.png");
//alert(ImagesArray.length);
MainMethods(ImagesArray);
function MainMethods(responseImages) {
//alert(responseImages.length);
var canvas = document.getElementById("product-image");
canvas.height = ($(window).height()) - 120;
canvas.width = canvas.height * 0.75;
var heightscreen = ($(window).height()) - 120;
var canvasheight = heightscreen;
var canvaswidth = canvas.height * 0.75;
canvaswidthdiv4 = 0;
var widthNeeded = canvasheight * 0.75;
var context = canvas.getContext('2d');
var returnedImages = loadImages(responseImages);
for (i = 0; i < returnedImages.length; i++) {
console.log(returnedImages[i]);
context.drawImage(returnedImages[i], canvaswidthdiv4, 55, widthNeeded, canvasheight);
}
// Image loading global variables
var loadcount = 0;
var loadtotal = 0;
var preloaded = false;
// Load images
function loadImages(imagefiles) {
// Initialize variables
loadcount = 0;
loadtotal = imagefiles.length;
preloaded = false;
// Load the images
var loadedimages = [];
for (var i = 0; i < imagefiles.length; i++) {
// Create the image object
var image = new Image();
// Add onload event handler
image.onload = function() {
loadcount++;
if (loadcount == loadtotal) {
// Done loading
preloaded = true;
}
};
// Set the source url of the image
image.src = imagefiles[i];
// Save to the image array
loadedimages[i] = image;
}
// Return an array of images
return loadedimages;
}
}
<canvas id="product-image" width="700" height="823"></canvas>
The problem is that your images are not loaded yet when you try to draw it.
Wrap the drawImage part in a function and call it when preloaded becomes true, here your boolean does nothing.
I refactored your code a little bit, you also had an issue with loadtotal being reset to 0 after your call to loadImage() function. So loadcountwon't ever be === loadtotal and your useless preloaded never switched to true.
var ImagesArray = new Array ("http://s4.postimg.org/dw8aujkkd/slim_Fit.png",
"http://s27.postimg.org/l6mq3hboz/outer_collar1.png",
"http://s22.postimg.org/e7alkm44x/inner_collar11.png",
"http://s12.postimg.org/h4kgdjn4t/maincolar.png",
"http://s13.postimg.org/edabwknfr/outer_fastening1.png");
function MainMethods(responseImages) {
var canvas = document.getElementById("product-image");
canvas.height = ($(window).height()) - 120;
canvas.width = canvas.height * 0.75;
var canvasheight = ($(window).height()) - 120;
var canvaswidth = canvas.height * 0.75;
canvaswidthdiv4 = 0;
var widthNeeded = canvasheight * 0.75;
var context = canvas.getContext('2d');
// an other error, if you set loadtotal to 0 after calling loadImages(), it will be set to 0 when images are loaded.
// and loadcount won't ever be === loadtotal.
var loadcount;
var loadtotal;
function loadImages(imagefiles) {
loadcount = 0;
loadtotal = imagefiles.length;
var loadedimages = [];
for (var i=0; i<imagefiles.length; i++) {
var image = new Image();
image.onload = function () {
loadcount++;
console.log(loadcount+'/'+ loadtotal);
if (loadcount == loadtotal) {
// done loading all the images
draw(loadedimages);
}
};
image.src = imagefiles[i];
loadedimages[i] = image;
}
}
// Wrap your drawing in a function that will be called asynchronously
function draw(loadedimages){
for (var i = 0; i < loadedimages.length; i++) {
console.log(loadedimages[i]);
context.drawImage(loadedimages[i], canvaswidthdiv4, 55, widthNeeded, canvasheight);
}
}
// Once all your variables are set, you can load the images
loadImages(responseImages);
}
MainMethods(ImagesArray);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<canvas id="product-image"></canvas>
Since it appears to be a browser specific issue, here's a hack to get it to work:
Replace : MainMethods(ImagesArray);
with : setTimeout(function () { MainMethods(ImagesArray); }, 0);
With timeout set to 0 ms, it would virtually execute instantaneously.
JsFiddle : http://jsfiddle.net/wdfrrayh/3/
Tested on IE, FF, Chrome
image src needs to be called after drawImage which i was doing before I have updated my function which is working fine,
below is working code for this
function loadImages(sources, callback, jsondata) {
var images = {};
var loadedImages = 0;
var numImages = 0;
// get num of sources
for(var src in sources) {
numImages++;
}
for(var src in sources) {
images[src] = new Image();
images[src].onload = function() {
if(++loadedImages >= numImages) {
callback(images);
}
};
images[src].src = sources[src];
}
}
var canvas = document.getElementById('product-image');
canvas.height = (jQuery(window).height()) -120;
canvas.width = canvas.height * 0.75;
var heightscreen = (jQuery(window).height()) -120;
var canvasheight = heightscreen;
var canvaswidth = canvas.height * 0.75;
canvaswidthdiv4 = 0;
var widthNeeded = canvasheight * 0.75;
var context = canvas.getContext('2d');
var sources = new Array ("http://s4.postimg.org/dw8aujkkd/slim_Fit.png",
"http://s27.postimg.org/l6mq3hboz/outer_collar1.png",
"http://s22.postimg.org/e7alkm44x/inner_collar11.png",
"http://s12.postimg.org/h4kgdjn4t/maincolar.png",
"http://s13.postimg.org/edabwknfr/outer_fastening1.png");
loadImages(sources, function(images) {
for(var i=0; i < sources.length; i++){
context.drawImage(images[i], canvaswidthdiv4, 55,widthNeeded,canvasheight);
}
});
I am actually trying to implement the functionality where I can add multiple images onto a canvas using array and kineticJs. I am unable to load images onto the canvas however these images are created outside the canvas body. I want to draw these circle images onto the canvas body. Cheers
<html>
<head>
<title>Bomb Game</title>
<link rel="stylesheet" type="text/css" href="style.css">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.3/jquery.min.js"></script>
<script src = "https://d3lp1msu2r81bx.cloudfront.net/kjs/js/lib/kinetic-v4.4.3.min.js"></script>
</head>
<body>
<div id = "container"></div>
<script>
window.onload = $(document).ready(function()
{
var bombLeft, bombTop, bombRight, bombBottom;
var timerLeft, timerTop, timerRight, timerBottom;
var numberCircles = [];
function loadImages(sources, callback)
{
var images = {};
var loadedImages = 0;
var numImages = 0;
// get num of sources
for(var src in sources)
{
numImages++;
}
for(var src in sources)
{
images[src] = new Image();
images[src].onload = function()
{
if(++loadedImages >= numImages)
{
callback(images);
}
};
images[src].src = sources[src];
}
}
var newCanvas = document.createElement("canvas");
var ctx = newCanvas.getContext("2d");
newCanvas.width = window.innerWidth;
newCanvas.height = window.innerHeight;
newCanvas.style.border = "10px solid #000000";
newCanvas.style.margin = "0px";
$("#container").append(newCanvas);
var sources = {background: 'bomb_artwork/background.jpg', bomb: 'bomb_artwork/bomb.png', timer: 'bomb_artwork/timer.png',
boxSmall: 'bomb_artwork/box_1.png',boxBig: 'bomb_artwork/box_2.png', numberCircle: 'bomb_artwork/number_circle.png', explode: 'bomb_artwork/explode.png'};
function initStage(images)
{
var stage = new Kinetic.Stage({
container: 'container',
width: newCanvas.width,
height: newCanvas.height
});
var layer = new Kinetic.Layer();
loadImages(sources,function(images){
<!-- For background image -->
ctx.drawImage(images.background,0,0,newCanvas.width,newCanvas.height);
x1 = newCanvas.width/7;
y1 = newCanvas.height/3;
x2 = newCanvas.width/8;
y2 = newCanvas.height/8;
<!-- To add boxes in background>
ctx.drawImage(images.boxBig,750,370,150,120);
ctx.drawImage(images.boxBig,754,270,150,120);
ctx.drawImage(images.boxSmall,788,210,120,80);
<!-- For bombbottom -->
bombBottom = images.bomb;
timerBottom = images.timer;
ctx.drawImage(bombBottom,newCanvas.width/2-newCanvas.width/8,newCanvas.height-150,x1,y1);
ctx.drawImage(timerBottom,newCanvas.width/2+newCanvas.width/10000,newCanvas.height-50,x2,y2);
ctx.font = "28pt Times New Roman";
ctx.fillStyle = "yellow";
ctx.fillText("Player 1", 720, 635);
ctx.font = "20pt Times New Roman";
ctx.fillStyle = "yellow";
ctx.fillText("? - 6 = 11", 730, 670);
<!-- For bombleft-->
bombLeft = images.bomb;
timerLeft = images.timer;
ctx.save();
ctx.rotate(Math.PI / 2);
ctx.drawImage(bombLeft,230,-newCanvas.height/4,x1,y1);
ctx.drawImage(timerLeft,400,-newCanvas.height/13,x2,y2);
ctx.restore();
<!-- For bombtop-->
bombTop = images.bomb;
timerTop = images.timer;
ctx.save();
ctx.translate(100, 100);
ctx.rotate(Math.PI);
ctx.drawImage(bombTop,-650,-50,x1,y1);
ctx.drawImage(timerTop,-480,50,x2,y2);
ctx.restore();
<!-- For bombright-->
bombRight = images.bomb;
timerRight = images.timer;
ctx.save();
ctx.translate(100, 100);
ctx.rotate(-Math.PI/2);
ctx.drawImage(bombRight,-325,1100,x1,y1);
ctx.drawImage(timerRight,-150,1215,x2,y2);
ctx.restore();
<!-- TO draw random circles -->
for(var i = 0; i < 30;i++)
{
numberCircles[i] = new Kinetic.Image({
image : images.numberCircle,
x : Math.floor(Math.random()* newCanvas.width),
y : Math.floor(Math.random()*newCanvas.height),
width : 50,
height : 50,
draggable : true,
stroke : 'red',
strokeWidth : 10,
strokeEnabled : false
/*if((x > newCanvas.width/8 && x < newCanvas.width-newCanvas.width/6)&&(y > newCanvas.height/4 && y < newCanvas.height-newCanvas.height/3))
{
ctx.drawImage(numberCircles[i],x,y,50,50);
}
else
{
i = i-1;
continue;
}*/
});
layer.add(numberCircles[i]);
stage.add(layer);
}
// use event delegation to update pointer style
// and apply borders
layer.on('mouseover', function(evt) {
//var shape = evt.shape;
document.body.style.cursor = 'pointer';
//shape.enableStroke();
layer.draw();
});
layer.on('mouseout', function(evt) {
//var shape = evt.shape;
document.body.style.cursor = 'default';
//shape.disableStroke();
layer.draw();
});
});
}
loadImages(sources,initStage);
});
</script>
</body>
</html>
Hi I'm trying to make a very simple game using javascripts canvas element. I have a rectangle thats drawn on the canvas and I would like for it to move across the canvas when user clicks a button but its not working.
here is my html:
<style>
canvas {
border: 1px solid black;
height: 300px;
width:500px;
}
</style>
</head>
<body>
<button id = "play">Click to play</button>
</body>
My javascript:
$( document ).ready(function() {
var x = document.createElement("CANVAS");
var ctx = x.getContext("2d");
ctx.fillStyle = "#FF0000";
var x1 = 10;
var y = 10;
ctx.fillRect(x1, y, 80, 10);
document.body.appendChild(x);
var Game = {stopped:true};;
Game.draw = function() {
ctx.fillRect(x1, y, 80, 10);
};
Game.update = function() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
x1 = x1+5;
};
Game.run = function() {
Game.update();
Game.draw();
};
$("#play").click(function() {
Game.stopped = false;
while (!Game.stopped){
Game.run();
}
});
});
There are multiple problems in your script.
there is no variable called, canvas it is x
Your loop is an infinite while loop, which does not give any time for the UI to update - since browser tab is a single threaded app both js execution and the repaint/refresh of the UI happens in the same thread
So
var interval;
$("#play").click(function () {
Game.stopped = false;
interval = setInterval(Game.run, 5);
});
$("#stop").click(function () {
Game.stopped = true;
clearInterval(interval);
});
Demo: Fiddle
There is another simple implement:
$(document).ready(function () {
var canvas = document.createElement("CANVAS");
var ctx = canvas.getContext("2d");
ctx.fillStyle = "#FF0000";
var x1 = 10;
var y = 10;
ctx.fillRect(x1, y, 80, 10);
document.body.appendChild(canvas);
var Game = {stopped: true};
;
Game.draw = function () {
ctx.fillRect(x1, y, 80, 10);
};
Game.update = function () {
ctx.clearRect(0, 0, canvas.width, canvas.height);
x1 = x1 + 5;
};
Game.run = function () {
Game.update();
Game.draw();
};
$("#play").click(function () {
Game.stopped = false;
// while (!Game.stopped) {
// Game.run();
// }
if(!Game.stopped){
setInterval(Game.run,1000);
}
});
});
For animation, it's better to use Window.requestAnimationFrame(), if you want to get a better performance.
I want to cycle through a list of images.
For each image, I'm trying to display it on a canvas, and to extract some information from it - in this example, it is as simple as it's width. The problem is that only the last image is displayed, and the values for the width are always undefined.
<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8">
</head>
<body>
<canvas id="canvas" width="100" height="100"></canvas>
<script>
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext('2d');
var paths = ['images/people/img_1.jpg', 'images/people/img_2.jpg', 'images/people/img_3.jpg'];
var width = new Array(3);
processImages();
function processImages() {
function display(img, i) {
canvas.width = img.width;
canvas.height = img.height;
ctx.drawImage(img, 0, 0);
width[i] = img.width;
alert("i = " + i);
}
for (var i = 0; i < 3; i++) {
var img = new Image();
img.onload = (function (x) {
return function() {
display(this, x);
}
})(i);
img.src = paths[i];
}
for (i = 0; i < 3; i++) {
document.write("<br>Image " + i + " width is: " + width[i]);
}
}
</script>
</body>
</html>
If you append the image to the HTML you can get width and height.
<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8">
</head>
<body>
<canvas id="canvas" width="100" height="100"></canvas>
<script>
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext('2d');
var paths = ['head.png', 'body.png', 'car.png'];
var width = new Array(3);
var body = document.getElementsByTagName('body')[0];
// save number of images loaded
var totalLoaded = 0;
processImages();
function processImages() {
function display(img, i) {
canvas.width = img.clientWidth;
canvas.height = img.clientHeight;
ctx.drawImage(img, 0, 0);
width[i] = img.clientWidth > 100;
}
for (var i = 0; i < 3; i++) {
var img = new Image();
img.onload = (function (x) {
return function() {
// append to the html
body.appendChild(this);
// now you have the width available
console.log(this.clientWidth);
// do whatever you need
display(this, x);
// remove the image
body.removeChild(this);
// check if all of the images were loaded
totalLoaded++
if(totalLoaded >= paths.length) {
onComplete();
}
}
})(i);
img.src = paths[i];
}
function onComplete () {
for (i = 0; i < 3; i++) {
document.write("<br>Image " + i + " width is: " + width[i]);
}
}
}
</script>
</body>
</html>
document.write is very, very old school and there are only really a couple of very specialised cases where it should be used. Try something like this instead:
<body>
<canvas id="canvas" width="100" height="100"></canvas>
<div id="w"></div>
<script>
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext('2d');
var paths = ['images/people/img_1.jpg', 'images/people/img_2.jpg', 'images/people/img_3.jpg'];
//var width = new Array(3);
processImages();
function processImages() {
function display(img, i) {
canvas.width = img.width;
canvas.height = img.height;
ctx.drawImage(img, 0, 0);
document.getElementById("w").innerHTML+="<br>Image " + i + " width is: " + img.width;
}
for (var i = 0; i < 3; i++) {
var img = new Image();
img.onload = (function (x) {
return function() {
display(this, x);
}
})(i);
img.src = paths[i];
}
}
</script>
</body>
image.onload is called asynchronously -- when the image loads, it fires an event that will execute that function. So the for loops will execute before onload functions are even called, and width will not contain anything when you are trying to write to the document.
So let's say I had this code:
var width = {};
for(var i = 0; i < 3; i++){
setTimeout(function(){
width[i] = i * 2;
}, 0);
}
for(var i = 0; i < 3; i++){
console.log(width[i]);
}
You would get undefined outputted every time since the timeout functions did not execute.
You see the last image after the code runs because you write to the same position in the canvas every time. You may want to either delay writing to the canvas or position the images somewhere else so they don't overlap, depending on what you intend on doing.