Merging javascript code with canvas animation - javascript

I’m trying to ‘merge’ some javascript code that changes pictures with a canvas that has also animation to it, without them cancelling eachother out. In this canvas there are some clouds that move and I want to throw kittens into it.
I understand this this might be a basic HTML5 canvas question but I’m terrible using canvas though. This is the first time I’m really working with it. Whenever I try to implement the code that applies to the kittens, the canvas screen just goes white and nothing shows.
I want to stick with most of the code that I have. I really want to keep the canvas the way it is and change nothing there but add those kittens in there too. Can someone puzzle out for me how to appropiately do this?
I'm guessing I would need to tweak the animation function somehow?
function animate(){
ctx.save();
ctx.clearRect(0, 0, cW, cH);
background.render();
foreground.render();
ctx.restore();
}
var animateInterval = setInterval(animate, 30);
}
The code is all in a FIDDLE, because it’s too much to show it on here.
EDIT: To be clear, I'm asking for the pictures of the kittens to be laid over the canvas, but I want the clouds in the canvas to overlay the kittens.

What you need to know is that the canvas element is transparent by default. So notice the minor change I made here :
body{
background:#667;
}
canvas {
width:50vw;
height:50vh;
margin-left: 20%;
}
#image {
border:#000 1px solid;
padding-left: 0;
padding-right: 0;
margin-left: auto;
margin-right: auto;
display: block;
width: 33%;
height: 100%;
position: relative;
top:140px;
z-index: -1;
}
#my_canvas{
border:#000 1px solid;
padding-left: 0;
padding-right: 0;
margin-left: auto;
margin-right: auto;
display: block;
width: 33%;
height: 100%;
}
<link href="css.css" rel="stylesheet" type="text/css">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<img src="" id="image"/>
<script>
var bg = new Image();
bg.src = "http://proverum.ru/templates/oblaka/img/cloud.png";
var fg = new Image();
fg.src = "http://www.tourisme-fumel.com/img_interf/meteo/cloudy.png";
function initCanvas(){
var lastTick = 0;
var position = { x:0, y:0 };
var rain = document.getElementById('rain');
var ctx = document.getElementById('my_canvas').getContext('2d');
var canvas_container = document.getElementById('my_canvas2');
var cW = ctx.canvas.width, cH = ctx.canvas.height;
function Background(){
this.x = 0, this.y = 0, this.w = bg.width, this.h = bg.height;
this.render = function(){
ctx.drawImage(bg, this.x--, 0);
if(this.x <= -250){
this.x = 0;
}
}
}
var background = new Background();
var image1 = "http://www.catsofaustralia.com/images/three_kittens.jpg";
var image2 = "http://thecatpalace.com.au/wp-content/uploads/2015/05/kitten1.jpg";
var image3 = "http://www.keepingkittens.com/images/cute-little-kitten-minka-rose-the-real-cinderella-story-21652512.jpg";
$(function() {
$("#image").prop("src", image1);
setInterval(function() {
$("#image").prop("src", image2);
setTimeout(function() {
$("#image").prop("src", image2);
setTimeout(function() {
$("#image").prop("src", image3);
}, 50);
setTimeout(function() {
$("#image").prop("src", image1);
}, 500);
}, 10);
}, 5000);
});
function Foreground(){
this.x = 0, this.y = 0, this.w = fg.width, this.h = fg.height;
this.render = function(){
ctx.drawImage(fg, this.x--, 0);
if(this.x <= -499){
this.x = 0;
}
}
}
var foreground = new Foreground();
function animate(){
ctx.save();
ctx.clearRect(0, 0, cW, cH);
background.render();
foreground.render();
ctx.restore();
}
var animateInterval = setInterval(animate, 30);
}
window.addEventListener('load', function(event) {
initCanvas();
});
</script>
</head>
<body>
<canvas id="my_canvas" width="611" height="864"></canvas>
<h1 id="status"></h1>
</body>
</html>
I just removed the
background:#FFF;
from the canvas css and the canvas became transparent.
How you will line up the canvas over the kittens is up to you, I just quickly used position:relative and z-index to prove my point.

Related

adding image inside html canvas using javascript not working

i am trying to create an image canvas where user can zoom into the image, the code which i got from here enter link description here, now i tried to add image inside it and i did the following code:
function draw(scale, translatePos) {
var canvas = document.getElementById("myCanvas");
var context = canvas.getContext("2d");
make_base(context);
}
function make_base(context) {
var base_image = new Image();
base_image.src = 'https://www.gstatic.com/webp/gallery3/1.sm.png';
base_image.onload = function() {
context.drawImage(base_image, 0, 0);
}
}
window.onload = function() {
var canvas = document.getElementById("myCanvas");
var translatePos = {
x: canvas.width / 2,
y: canvas.height / 2
};
var scale = 1.0;
var scaleMultiplier = 0.8;
var startDragOffset = {};
var mouseDown = false;
// add button event listeners
document.getElementById("plus").addEventListener("click", function() {
scale /= scaleMultiplier;
draw(scale, translatePos);
}, false);
document.getElementById("minus").addEventListener("click", function() {
scale *= scaleMultiplier;
draw(scale, translatePos);
}, false);
// add event listeners to handle screen drag
canvas.addEventListener("mousedown", function(evt) {
mouseDown = true;
startDragOffset.x = evt.clientX - translatePos.x;
startDragOffset.y = evt.clientY - translatePos.y;
});
canvas.addEventListener("mouseup", function(evt) {
mouseDown = false;
});
canvas.addEventListener("mouseover", function(evt) {
mouseDown = false;
});
canvas.addEventListener("mouseout", function(evt) {
mouseDown = false;
});
canvas.addEventListener("mousemove", function(evt) {
if (mouseDown) {
translatePos.x = evt.clientX - startDragOffset.x;
translatePos.y = evt.clientY - startDragOffset.y;
draw(scale, translatePos);
}
});
draw(scale, translatePos);
};
jQuery(document).ready(function() {
$("#wrapper").mouseover(function(e) {
$('#status').html(e.pageX + ', ' + e.pageY);
});
})
body {
margin: 0px;
padding: 0px;
}
#wrapper {
position: relative;
border: 1px solid #9C9898;
width: 578px;
height: 200px;
}
#buttonWrapper {
position: absolute;
width: 30px;
top: 2px;
right: 2px;
}
input[type="button"] {
padding: 5px;
width: 30px;
margin: 0px 0px 2px 0px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
<body onmousedown="return false;">
<div id="wrapper">
<canvas id="myCanvas" width="578" height="200">
</canvas>
<div id="buttonWrapper">
<input type="button" id="plus" value="+"><input type="button" id="minus" value="-">
</div>
</div>
<h2 id="status">
0, 0
</h2>
</body>
however the image is not getting displayed inside the canvas, can anyone please tell me what could be wrong in here, thanks in advance
Your draw function never actually draws to the canvas. You get the canvas and context in the first 2 lines, but you need to call drawImage with the image to actually add it to the canvas itself.
I suspect you want to be calling make_base inside it like so:
function draw(scale, translatePos) {
var canvas = document.getElementById("myCanvas");
var context = canvas.getContext("2d");
make_base();
}
You also need to have the context in the same scope as you use it. At the moment, the variable context only exists inside the draw function and not the make_base function, so you can't access it from inside make_base.
You can pass it as a variable like so:
function draw(scale, translatePos) {
var canvas = document.getElementById("myCanvas");
var context = canvas.getContext("2d");
make_base(context);
}
function make_base(context) {
var base_image = new Image();
base_image.src = 'a2.jpg';
base_image.onload = function() {
context.drawImage(base_image, 0, 0);
}
}
Every time you want to change anything on an HTML canvas you need to call draw functions to change what's there.

Is there a way to fix lagging when scrolling a large canvas?

I'm trying to implement a parallax scrolling effect with vanilla JS/HTML/CSS; what I've implemented already works, but there seems to be a lag with the undermost background canvas (I've made three canvases, one to hold the player/other obstacles, one to hold a background, and one to hold a foreground). The lagging seems to be only happening with the background (not the foreground).
// Drawing the background
draw() {
this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height);
// Preventing browser(s) from smoothing out/blurring lines
this.ctx.mozImageSmoothingEnabled = false;
this.ctx.webkitImageSmoothingEnabled = false;
this.ctx.msImageSmoothingEnabled = false;
this.ctx.imageSmoothingEnabled = false;
this.ctx.drawImage(this.image, this.posX, 0, this.image.width, this.image.height, 0, 0, this.canvas.width, this.canvas.height);
this.ctx.drawImage(this.image, this.posX - this.image.width, 0, this.image.width, this.image.height, 0, 0, this.canvas.width, this.canvas.height);
if (this.image.width > this.canvas.width) {
this.ctx.drawImage(this.image, this.x - this.image.width * 2, 0);
}
if (this.posX >= this.image.width) {
this.posX = 0;
}
this.scrollImage();
}
// Scrolls an image
scrollImage() {
this.posX += this.speed;
}
I've tried using whole numbers for the speed to avoid calculating decimal pixel sizes and after looking at some other posts with this problem, it seems like workarounds are difficult to find. (Actually, I'm not quite sure if this is exactly my problem, but that's the only reason for the lag that I can think of). It is strange that the foreground is scrolling seamlessly though.
Here's everything that you'll need to reproduce the problem (I won't post the entire code files since it'll be too long, but I'm sure people can gather the remaining boiler plate form of the files):
// index.html
<body>
<canvas id="background-canvas"></canvas>
<canvas id="foreground-canvas" height="302" width="802"></canvas>
<div class="overlay-wrapper"></div>
<canvas id="game-canvas" tabindex="1"></canvas>
<p>Press tab to play</p>
</body>
// index.js
const Game = require('./game');
document.addEventListener('DOMContentLoaded', function () {
// Getting main game canvas
const gameCanvas = document.getElementById('game-canvas');
const gameCanvasCtx = gameCanvas.getContext('2d');
// Parallax scrolling effect
// Getting background canvas
const backgroundCanvas = document.getElementById('background-canvas');
const backgroundCanvasCtx = backgroundCanvas.getContext('2d');
// Getting foreground canvas
const foregroundCanvas = document.getElementById('foreground-canvas');
const foregroundCanvasCtx = foregroundCanvas.getContext('2d');
const game = new Game(
gameCanvasCtx,
gameCanvas,
backgroundCanvasCtx,
backgroundCanvas,
foregroundCanvasCtx,
foregroundCanvas
);
game.start();
});
// game.js
class Game {
// Constructor for game
constructor(gameCtx, gameCanvas, backgroundCtx, backgroundCanvas, foregroundCtx, foregroundCanvas) {
// Setting context and canvas
this.gameCtx = gameCtx;
this.gameCanvas = gameCanvas;
this.backgroundCtx = backgroundCtx;
this.backgroundCanvas = backgroundCanvas;
this.foregroundCtx = foregroundCtx;
this.foregroundCanvas = foregroundCanvas;
// Setting game state
this.gameOver = false;
this.paused = false;
// Binding class methods
this.draw = this.draw.bind(this);
// Creating background and foreground
this.createBackground(this.backgroundCtx, this.backgroundCanvas, this.foregroundCtx, this.foregroundCanvas);
}
// Creating the background and foreground
createBackground(backgroundCtx, backgroundCanvas, foregroundCtx, foregroundCanvas) {
// Background
const backgroundImage = new Image();
backgroundImage.src = '../dist/assets/images/background.png';
backgroundImage.alt = 'Background';
this.background = new Background(backgroundCtx, backgroundCanvas, backgroundImage, 1);
// Foreground
const foregroundImage = new Image();
foregroundImage.src = '../dist/assets/images/foreground.png';
this.foreground = new Background(foregroundCtx, foregroundCanvas, foregroundImage, 10);
}
// Drawing the game
draw() {
if (!this.gameOver) {
requestAnimationFrame(this.draw);
// Drawing background
this.background.draw();
this.foreground.draw();
}
}
// temp start function for game
start() {
this.draw();
}
}
// background.js
class Background {
// Constructor for background
constructor(ctx, canvas, image, speed) {
this.ctx = ctx;
this.canvas = canvas;
this.image = image;
this.speed = speed;
this.posX = 0;
}
// Drawing the background
draw() {
this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height);
// Preventing browser(s) from smoothing out/blurring lines
this.ctx.mozImageSmoothingEnabled = false;
this.ctx.webkitImageSmoothingEnabled = false;
this.ctx.msImageSmoothingEnabled = false;
this.ctx.imageSmoothingEnabled = false;
this.ctx.drawImage(this.image, this.posX, 0, this.image.width, this.image.height, 0, 0, this.canvas.width, this.canvas.height);
this.ctx.drawImage(this.image, this.posX - this.image.width, 0, this.image.width, this.image.height, 0, 0, this.canvas.width, this.canvas.height);
if (this.image.width > this.canvas.width) {
this.ctx.drawImage(this.image, this.x - this.image.width * 2, 0);
}
if (this.posX >= this.image.width) {
this.posX = 0;
}
this.scrollImage();
}
// Scrolls an image
scrollImage() {
this.posX += this.speed;
}
}
And in my css file, this is how I styled my canvases:
body {
width: 100vw;
height: 100vh;
overflow: hidden;
}
/* For rendering sprites without blurring */
canvas {
image-rendering: pixelated;
}
/* Canvas styling */
#game-canvas {
position: absolute;
top: 0;
left: 0;
tabindex: 1;
width: 100%;
height: 100%;
z-index: 3;
}
#background-canvas {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
z-index: 0;
}
#foreground-canvas {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
z-index: 1;
}
.overlay-wrapper {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: rgba(0, 0, 0, 0.25);
z-index: 2;
}

How do I make multiple moving squares on a canvas?

So far I have made a moving square that when the button is clicked in the HTML file, calls the draw() function and draws a red square in the canvas area that moves accross the canvas. How do I make it so that the same function draw() can create multiple moving sqaures?
Here's the code so far:
var x = 10;
var y = 10;
function draw(){
var can = document.getElementById("myCanvas");
var ctx = can.getContext("2d");
var x = 1;
setInterval(function(){
ctx.clearRect(0,0, can.width, can.height);
ctx.fillRect(x, 20, 75, 75);
ctx.fillStyle ="red";
x=x+5;
}, 500
);
}
Not sure that my solution is good, I'm just starting to learn js, but hope it will helpful.
// variables declaration. I suggest to use Arrays
// for store individual rectangle parameters.
// rectangle start coords x and y
var rcx = [];
var rcy = [];
// delta to move x, y
var dx = [];
var dy = [];
// rectangle size (if you want it variable)
var size =[];
// init canvas
let canvas = document.getElementById('canvas');
let ctx = canvas.getContext('2d');
// create and collect rectangles parameters
// on window load (here 100 rectangles created)
// with unique coords, deltas to move,
// and sizes for each rectangle.
window.onload = function() {
for (var i=0; i<100; i++) {
// in this solution all parameters randomized,
// but you can set whatever you want.
rcx[i]=(Math.floor(Math.random() * Math.floor(canvas.width)));
rcy[i]=(Math.floor(Math.random() * Math.floor(canvas.height)));
dx[i]= (Math.floor(Math.random() * Math.floor(3))-1);
dy[i]=(Math.floor(Math.random() * Math.floor(3))-1);
size[i] = (Math.floor(Math.random() * Math.floor(8)));
}};
// it is optional, but i decide
// made function for rectangle declaration.
// It will looks more compact when rendering.
function rect(x, y, size){
ctx.fillRect(x, y, size, size/2 );
ctx.fillStyle = "rgba(255,255,255,1)";
}
// finally all together into function draw()
function draw(){
setInterval(function(){
ctx.clearRect(0,0, canvas.width, canvas.height);
for (var j=0; j<100; j++) {
// read arrays
// render rectangle with params from arrays
rect(rcx[j],rcy[j],size[j]);
// add delta to move (x,y)
// and rewrite new coords to arrays
rcx[j]=rcx[j]+dx[j];
rcy[j]=rcy[j]+dy[j]};
}, 100
);
};
//rendering animation
draw();
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
<style>
#canvas {
width: 500px;
height: 500px;
background-color: #ccc;
}
</style>
</head>
<body>
<canvas id="canvas"></canvas>
<script src="js1.js"></script>
</body>
</html>
Sorry, didn't mention about button. So for the btn changes are simple.
Create btn div in html,
Add listener on this div. Рut params in arrays if button is pushed. Instead of generation by random as it was in my solution before.
Read arrays and render all rectangles from it.
// variables declaration. I suggest to use Arrays for store individual rectangle parameters.
// rectangle start coords x and y
var rcx = [];
var rcy = [];
// delta to move x, y
var dx = [];
var dy = [];
// rectangle size (if you want it variable)
var size =[];
//counter for created rectangles
var i=0;
// init canvas
let canvas = document.getElementById('canvas');
let ctx = canvas.getContext('2d');
// create and collect rectangles parameters on btn push
// with unique coords, deltas to move, and sizes for each rectangle.
var btn =document.getElementById('btn');
btn.addEventListener( 'click', function() {
//count every time you push the btn and create rect
i=i+1;
//generate rect params x,y, delta x, delta y, size
rcx[i]=20;
rcy[i]=20;
dx[i]=1
dy[i]=0
size[i] = 8;
});
// it is optional, but i decide made function for rectangle declaration. It will looks more compact when rendering.
function rect(x, y, size){
ctx.fillRect(x, y, size, size/1.5);
ctx.fillStyle = "red";
}
// finally all together into function draw()
function draw(){
setInterval(function(){
ctx.clearRect(0,0, canvas.width, canvas.height);
for (var j=1; j<rcx.length; j++) {
// read arrays
// render rectangle with params from arrays
rect(rcx[j],rcy[j],size[j]);
// add delta to move (x,y) and rewrite new coords to arrays
rcx[j]=rcx[j]+dx[j];
rcy[j]=rcy[j]+dy[j]};
}, 100
);
};
//rendering animation
draw();
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
<style>
body{
margin: 0 auto;
padding: 0;
background-color: rgb(17, 0, 28);
}
#container{
position: relative;
margin-top: 10px;
margin-left: 50px;
}
#canvas {
z-index: 0;
position:fixed;
align-self: center;
justify-self: center;
width: 80vw;
height: 50vw;
background-color: #ccc;
}
#btn {
margin: 20px 20px 20px 0px;
padding: 10px;
position:static;
top: 30px;
font-family: 'Roboto', sans-serif;
width: 65px;
background-color: brown;
cursor: pointer;
}
#btn:hover {
background-color: red;
}
#btn:active {
background-color: coral;
}
</style>
</head>
<body>
<div id="container">
<div id="btn"> Push me </div>
<canvas id="canvas"></canvas>
</div>
<script src="js1.js"></script>
</body>
</html>

Setting image size percentage in canvas and jquery

I'm trying to create a one-pager at the moment with a canvas where you can click to add/place images at random. I've gotten most of what I want to work, but being extremely new to jquery and canvas, I still can't figure out how to set a max-size for my images. As far as I've understood, it can be quite hard to make images on a canvas work perfectly when you haven't set the canvas size manually in css, but I have a resizing canvas, so I'm not really sure how I get around that.
I want the images that I place to have a max-height/max-width of 80% of the viewport. I tried setting a max size in css, but it didn't do anything.
Here's a jsfiddle
$(document).ready(function () {
var images = [];
$("#siteload").fadeIn(1500);
$('.put').each(function() {
images.push($(this).attr('src'));
});
(function() {
var
htmlCanvas = document.getElementById('c'),
context = htmlCanvas.getContext('2d');
initialize();
img = new Image();
count = 0;
htmlCanvas.onclick= function(evt) {
img.src = images[count];
var x = evt.offsetX - img.width/2,
y = evt.offsetY - img.height/2;
context.drawImage(img, x, y);
count++;
if (count == images.length) {
count = 0;
}
}
function initialize() {
window.addEventListener('resize', resizeCanvas, false);
resizeCanvas();
}
function resizeCanvas() {
htmlCanvas.width = window.innerWidth;
htmlCanvas.height = window.innerHeight;
}
})();
});
$(".hvr_cnt").mouseenter(function () {
title = $("<div class='hvr_ttl'>" + $(this).children()[0].title + "</div>");
$(this).children()[0].title = "";
$(this).append(title);
});
$(document).mousemove(function(e){
$('.hvr_ttl').css({
top: e.pageY - $(".hvr_ttl").height()/2,
left: e.pageX - $(".hvr_ttl").width()/2
});
});
$(".hvr_cnt").mouseleave(function (e) {
$(this).children()[0].title = $($(this).children()[1]).html();
$(this).children()[1].remove();
});
body {
margin: 0;
padding: 0;
background: rgb(240, 240, 240);
width: 100%;
height: 100%;
border: 0;
color: rgb(40, 40, 40);
overflow: hidden;
display: block;
}
.slides {
display: none
}
#c {
display: block;
position: absolute;
left: 0px;
top: 0px;
}
.hvr_ttl {
display: block;
position: absolute;
pointer-events: none;
cursor: none;
}
.hvr_cnt {
cursor: none;
padding: none;
margin: none;
}
<body ontouchstart="">
<div class="hvr_cnt">
<canvas id="c" title="click"></canvas>
</div>
<ul class="slides">
<li><img src="https://upload.wikimedia.org/wikipedia/commons/thumb/8/85/Smiley.svg/2000px-Smiley.svg.png" class="put" /></li>
<li><img src="https://emojipedia-us.s3.amazonaws.com/thumbs/160/google/56/thumbs-up-sign_1f44d.png" class="put" /></li>
</ul>
</body>
Any help would be appreciated :)
Try this :
htmlCanvas.onclick= function(evt) {
img.src = images[count];
img.width = 80/100* htmlCanvas.width;
img.height = 80/100* htmlCanvas.height;
var x = evt.offsetX - img.width/2,
y = evt.offsetY - img.height/2;
// context.drawImage(img, x, y);
context.drawImage(img, x, y, img.width, img.height);
count++;
if (count == images.length) {
count = 0;
}
}
context.drawImage(img, 0, 0,img.width,img.height,0,0,htmlCanvas.width,htmlCanvas.height);
you also can use background-size:cover;
The max-height/width doesn't work because everything within the canvas is independent from your css.
If you want to set the image to 80% use htmlCanvas.width and htmlCanvas.height to calculate the new size and use context.drawImage(img, x, y, w, h) to set the image size when drawing.
Maybe this post could be helpful.

Optimise HTML5 canvas

Why does html5 canvas become very slow when I draw 2000 images and more ?
How can I optimise it?
Here's a demo that I've made, disable the "safe mode" by left clicking on the canvas and start moving your mouse until you get ~2000 images drawn
var img = new Image()
img.src = "http://i.imgur.com/oVOibrL.png";
img.onload = Draw;
var canvas = $("canvas")[0];
var ctx = canvas.getContext("2d")
var cnv = $("canvas");
var draw = [];
$("canvas").mousemove(add)
function add(event) {
draw.push({x: event.clientX, y: event.clientY})
}
canvas.width = cnv.width();
canvas.height = cnv.height();
var safe = true;
cnv.contextmenu(function(e) { e.preventDefault() })
cnv.mousedown(function(event) {
if(event.which == 1) safe = !safe;
if(event.which == 3) draw = []
});
function Draw() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
requestAnimationFrame(Draw);
for(var i of draw) {
ctx.drawImage(img, i.x, i.y)
}
if(safe && draw.length > 300) draw = []
ctx.fillText("Images count: "+ draw.length,10, 50);
ctx.fillText("Left click to toggle the 300 images limit",10, 70);
ctx.fillText("Right click to clear canvas",10, 90);
}
Draw();
body {
margin: 0;
padding: 0;
width: 100%;
height: 100%;
position: absolute;
}
canvas {
position: absolute;
width: 100%;
height: 100%;
z-index: 99999999999;
cursor: none;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<canvas></canvas>
Codepen: http://codepen.io/anon/pen/PpeNme
The simple way with the actual code :
Don't redraw all your images at this rate.
Since in your example, the images are static, you actually don't need to redraw everything every frame : Just draw the latest ones.
Also, if you've got other drawings occurring (e.g your texts), you may want to use an offscreen canvas for only the images, that you'll redraw on the onscreen canvas + other drawings.
var img = new Image()
img.src = "http://i.imgur.com/oVOibrL.png";
img.onload = Draw;
var canvas = $("canvas")[0];
var ctx = canvas.getContext("2d")
var cnv = $("canvas");
var draw = [];
$("canvas").mousemove(add)
function add(event) {
draw.push({
x: event.clientX,
y: event.clientY
})
}
canvas.width = cnv.width();
canvas.height = cnv.height();
// create an offscreen clone of our canvas for the images
var imgCan = canvas.cloneNode();
var imgCtx = imgCan.getContext('2d');
var drawn = 0; // a counter to know how much image we've to draw
var safe = true;
cnv.contextmenu(function(e) {
e.preventDefault()
})
cnv.mousedown(function(event) {
if (event.which == 1) safe = !safe;
if (event.which == 3) draw = []
});
function Draw() {
// clear the visible canvas
ctx.clearRect(0, 0, canvas.width, canvas.height);
requestAnimationFrame(Draw);
if (draw.length) { // onmy if we've got some objects to draw
for (drawn; drawn < draw.length; drawn++) { // only the latest ones
let i = draw[drawn];
// draw it on the offscreen canvas
imgCtx.drawImage(img, i.x, i.y)
}
}
// should not be needed anymore but...
if (safe && draw.length > 300) {
draw = [];
drawn = 0; // reset our counter
// clear the offscren canvas
imgCtx.clearRect(0, 0, canvas.width, canvas.height);
}
// draw the offscreen canvas on the visible one
ctx.drawImage(imgCan, 0, 0);
// do the other drawings
ctx.fillText("Images count: " + draw.length, 10, 50);
ctx.fillText("Left click to toggle the 300 images limit", 10, 70);
ctx.fillText("Right click to clear canvas", 10, 90);
}
Draw();
body {
margin: 0;
padding: 0;
width: 100%;
height: 100%;
position: absolute;
}
canvas {
position: absolute;
width: 100%;
height: 100%;
z-index: 99999999999;
cursor: none;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<canvas></canvas>
Now, if you need these images to be dynamic (i.e move at every frame), you may consider using imageDatas.
You can see this original post by user #Loktar, which explains how to parse your drawn image imageData, and then redraw it pixel per pixel on the visible canvas' imageData. You can also see this follow-up Q/A, which provides a color implementation of Loktar's idea.
On small images, this actually improves drastically the performances, but it has the huge inconvenient to not support alpha channel multiplication. You will only have fully transparent and fully opaque pixels. An other cons is that it may be harder to implement, but this is just your problem ;-)

Categories