HTML5 drawImage - Not working in Chrome while dragging - javascript

Im trying to drag and drop an image in canvas. But when dragging in chrome the image disapears but in Mozilla it works fine. Any help on this would be really appreciated.
HTML File
<head>
<script>
var canvasImages = [];
function imageProp() {
this.imgName = ' ';
this.imgX = 0;
this.imgY = 0;
this.ImgWidth = 1;
this.ImgHeight = 1;
}
function GetFilename(url) {
if (url) {
var m = url.toString().match(/.*\/(.+?)\./);
if (m && m.length > 1) {
return m[1];
}
}
return "";
}
function load(source) {
var canvas = document.getElementById("mycanvas");
var ctx = canvas.getContext('2d');
var imageObj = new Image();
//Loading image to Canvas
imageObj.onload = function () {
ctx.drawImage(imageObj, 0, 0);
};
imageObj.src = source;
//Inserting properties of image loaded in canvas to an array
var Property = new imageProp;
//Property.imgName = GetFilename(source);
Property.imgName = source;
Property.imgX = 0;
Property.imgY = 0;
Property.ImgWidth = imageObj.width;
Property.ImgHeight = imageObj.height;
canvasImages.push(Property);
}
</script>
</head>
<body>
<img id = "imgID" onclick=" load(this.src)" src = 'download.png'/>
<canvas id="mycanvas" width="1000" height="1000">HTML5 Not Supported</canvas>
<script src="Canvas_js.js"></script>
</body>
Javascript file
(function () {
"use strict";
/*global document*/
/*global clear*/
/*global canvasImages*/
/*jslint devel: true */
/*jslint browser: true */
var canvas, ctx, ghostcanvas, gctx, RedrawInterval = 20, canvasValid = false, clickLoc = {}, isDragging = false, index = 0, selectedIndex = 0;
clickLoc.x = 0;
clickLoc.y = 0;
function drawCanv() {
var i = 0, imageObj;
ctx.clearRect(0, 0, canvas.width, canvas.height);
for (i = 0; i < canvasImages.length; i += 1) {
imageObj = new Image();
imageObj = document.createElement('img');
imageObj.src = canvasImages[i].imgName;
imageObj.onload = function () {
ctx.drawImage(imageObj, canvasImages[i].imgX, canvasImages[i].imgY);
};
}
}
function resizeHandler(index) {
ctx.beginPath();
ctx.strokeRect(canvasImages[index].imgX, canvasImages[index].imgY, canvasImages[index].ImgWidth + 5, canvasImages[index].ImgHeight + 5);
}
function canvasOnClick(e) {
var rect, i = 0;
isDragging = true;
//Get X and Y coordinates of the click
rect = canvas.getBoundingClientRect();
clickLoc.x = e.clientX - rect.left;
clickLoc.y = e.clientY - rect.top;
//Check whether any image is clicked
for (i = 0; i < canvasImages.length; i += 1) {
if (clickLoc.x >= canvasImages[i].imgX && clickLoc.x <= canvasImages[i].imgX + canvasImages[i].ImgWidth && clickLoc.y >= canvasImages[i].imgY && clickLoc.y <= canvasImages[i].imgY + canvasImages[i].ImgHeight) {
selectedIndex = i;
resizeHandler(i);
}
}
}
function canvasMouseUp(e) {
isDragging = false;
}
function canvasMouseMove(e) {
if (isDragging === true) {
canvasImages[selectedIndex].imgX += 5;
drawCanv();
}
}
function init() {
// Defining Canvas and fake canvas
canvas = document.getElementById('mycanvas');
ctx = canvas.getContext('2d');
ghostcanvas = document.createElement('canvas');
ghostcanvas.height = canvas.height;
ghostcanvas.width = canvas.width;
gctx = ghostcanvas.getContext('2d');
// Redrawing canvas for the interval
//setInterval(draw, RedrawInterval);
// Adding Eventlisteners
canvas.addEventListener("mousedown", canvasOnClick, false);
canvas.addEventListener("mouseup", canvasMouseUp, false);
canvas.addEventListener("mousemove", canvasMouseMove, false);
}
init();
}());

Start messing around with
user-select: none;
-webkit-user-select: none;
in your css.

Related

How to position image on canvas same as overlaped div of same dimension

I have two div of same dimension which overlap each other using z-index.
Ist div contain image and 2nd div contain a canvas
I am trying to draw image on canvas same place as Ist div. I am using hammerjs library to zoomin/out , reposition and rotate image. I found these code somewhere else
function getMeta(url){
img = new Image();
var remoteImage = {}
img.src = url;
remoteImage.width = img.naturalWidth
remoteImage.height = img.naturalHeight
remoteImage.src = url;
return remoteImage
}
var urlImage = getMeta('https://www.penghu-nsa.gov.tw/FileDownload/Album/Big/20161012162551758864338.jpg')
var text = document.querySelector("#text");
var oImg=document.querySelector("#img_scan");
oImg.style['transition-duration'] = '100ms';
var timeInMs = 0;
var preAngle = 0;
var rotateAngle = 0;
var preRotation = 0;
var originalSize = {
width : oImg.offsetWidth,
height : oImg.offsetHeight,
}
var current = {
x : 0,
y : 0,
z : 1,
angle : 0,
width: originalSize.width,
height: originalSize.height,
}
var last = {
x : 0,
y : 0,
z : 1,
}
var oImgRec = oImg.getBoundingClientRect();
var cx = oImgRec.left + oImgRec.width * 0.5;
var cy = oImgRec.top + oImgRec.height * 0.5;
var imageCenter = {
x:cx,
y:cy
}
var pinchImageCenter = {}
var deltaIssue = { x: 0, y: 0 };
var pinchStart = { x: undefined, y: undefined, isPanend:false}
var panendDeltaFix = {x:0,y:0,isPanend:false}
var pinchZoomOrigin = undefined;
var lastEvent = ''
var hammer = new Hammer(oImg);
hammer.get('pinch').set({enable: true});
hammer.get('pan').set({direction: Hammer.DIRECTION_ALL}).recognizeWith(hammer.get('pinch'));
hammer.on("pinchstart", function(e) {
last.x = current.x;
last.y = current.y;
pinchStart.x = e.center.x;
pinchStart.y = e.center.y;
pinchImageCenter = {
x: imageCenter.x + last.x,
y: imageCenter.y + last.y
}
lastEvent = 'pinchstart';
});
hammer.on("pinchmove", function(e) {
if(preAngle == 0){
preAngle = Math.round(e.rotation);
preRotation = Math.round(e.rotation);
}else{
if(Math.abs(Math.round(e.rotation)-preRotation)>=300){
if(e.rotation > 0){
preAngle+=360;
}else if(e.rotation < 0){
preAngle-=360;
}
}
current.angle = rotateAngle + (Math.round(e.rotation)-preAngle);
preRotation = Math.round(e.rotation);
}
var newScale = (last.z * e.scale) >= 0.1 ? (last.z * e.scale) : 0.1;
var d = scaleCal(e.center, pinchImageCenter, last.z, newScale)
current.x = d.x + last.x;
current.y = d.y + last.y;
current.z = d.z + last.z;
update();
lastEvent = 'pinchmove';
});
hammer.on("pinchend", function(e) {
last.x = current.x;
last.y = current.y;
last.z = current.z;
rotateAngle = current.angle;
preAngle = 0;
lastEvent = 'pinchend';
});
hammer.on("panmove", function(e) {
var panDelta = {
x:e.deltaX,
y:e.deltaY
}
if (lastEvent !== 'panmove') {
deltaIssue = {
x: panDelta.x,
y: panDelta.y
}
}
current.x = (last.x+panDelta.x-deltaIssue.x);
current.y = (last.y+panDelta.y-deltaIssue.y);
lastEvent = 'panmove'
update();
});
hammer.on("panend", function(e) {
last.x = current.x;
last.y = current.y;
lastEvent = 'panend';
});
hammer.on('tap', function(e) {
if((Date.now()-timeInMs)<300){
if(last.z > 1){
last.z = 1;
current.z = 1;
update();
}else if(last.z <= 1){
last.z = 2;
current.z = 2;
update();
}
}
timeInMs = Date.now();
lastEvent = 'tap';
});
function scaleCal(eCenter, originCenter, currentScale, newScale) {
var zoomDistance = newScale - currentScale;
var x = (originCenter.x - eCenter.x)*(zoomDistance)/currentScale;
var y = (originCenter.y - eCenter.y)*(zoomDistance)/currentScale;
var output = {
x: x,
y: y,
z: zoomDistance
}
return output
}
function update() {
current.height = originalSize.height * current.z;
current.width = originalSize.width * current.z;
if(current.z < 0.1){
current.z = 0.1;
}
oImg.style.transform = " translate3d(" + current.x + "px, " + current.y + "px, 0)rotate("+current.angle+"deg)scale("+current.z+")"
}
So by above code user can zoomin/zoom out , rotate image . After they set image in their desired position i am putting that image on canvas so i can use dataurl method to save image later.
I tried below code to draw image on canvas same place as div ,same dimension and with same angle but sadly image is not getting exactly same positioned as div
var canvas = document.getElementById('canvas');
var ctx = canvas.getContext('2d');
$("#btn").click(copyoncanvas);
function copyoncanvas(){
var bound=objimg.getBoundingClientRect();
var objimg=new Image();
objimg.src="https://www.penghu-nsa.gov.tw/FileDownload/Album/Big/20161012162551758864338.jpg";
ctx.drawImage(objimg,bound.left,bound.top,current.width,current.height);
drawRotated(current.angle,bound.left,bound.top);
}
function drawRotated(degrees,l,t){
const objimg=document.getElementById("img_scan");
ctx.clearRect(0,0,canvas.width,canvas.height);
ctx.save();
var x=canvas.width/2;
var y=canvas.height/2;
ctx.translate(x,y);
ctx.rotate(degrees * Math.PI/180);
ctx.drawImage(objimg,-l,-t,current.width,current.height);
ctx.restore();
}
I think my problem is with drawrotated function because it work fine without using it but i want to rotate image on canvas too
HTML
<div id="container">
<div class="box"><canvas id="canvas"></canvas></div>
<div id="imgcont">
<img src="https://www.penghu-nsa.gov.tw/FileDownload/Album/Big/20161012162551758864338.jpg" id="img_scan" class="img-custom-img2"/>
</div>
</div>
<button id="btn">Copy on canvas</button>
CSS
#container{
position:relative;margin: 0px;
padding:0px;background:#ff0;
top:0px; overflow:hidden;
width:300px;
border:1px solid #000; height:250}
#img_scan,.box{
width:100%; height:100%;
position: absolute;
top: 0;
left: 0; margin:0; padding:0px
}
.box{z-index:98;height:250}
#canvas{width:100%;margin:0;
padding:0;
width:300;height:250}
#img_scan{width:300px;height:250px}
#imgcont{width:100%;height:250px;z-index:99}

How to pause the animation

I make this image move around the canvas but none of the methods stop it from moving.I make the setInterval to make the move and clear the Interval later by clearInterval in order to stop the motion but seems it won't work
<html>
<head>
<script type="application/javascript">
var ctx = null;
var x_icon = 0;
var y_icon = 0;
var stepX = 1;
var stepY = 1;
var size_x = 221;
var size_y = 184;
var canvas_size_x = 800;
var canvas_size_y = 600;
var anim_img = null;
function draw() {
var canvas = document.getElementById("canvas");
ctx = canvas.getContext("2d");
anim_img = new Image(size_x, size_y);
anim_img.onload = function() {
var myvar = setInterval(myAnimation, 10);
function stopMove() {
clearInterval(myVar);
}
}
anim_img.src = 'image/download.jpg';
}
function myAnimation() {
ctx.clearRect(0, 0, canvas_size_x, canvas_size_y);
if (x_icon < 0 || x_icon > canvas_size_x - size_x) {stepX = -stepX; }
if (y_icon < 0 || y_icon > canvas_size_y - size_y) {stepY = -stepY; }
x_icon += stepX;
y_icon += stepY;
ctx.drawImage(anim_img, x_icon, y_icon);
}
</script>
</head>
<body onload="draw();">
<canvas id="canvas" width="800" height="600" style="border:solid 1px;"></canvas>
<button onmousedown="stopMove()">STOP</button>
</body>
</html>
I expected to stop the motion of the download.jpg on click of the STOP button but it won't work
As #Snel23 said, you need to lift stopMove() and myvar out from the draw() context.
var ctx = null;
var x_icon = 0;
var y_icon = 0;
var stepX = 1;
var stepY = 1;
var size_x = 221;
var size_y = 184;
var canvas_size_x = 800;
var canvas_size_y = 600;
var anim_img = null;
var myvar = null; // moving interval handle outside draw()
function draw() {
var canvas = document.getElementById("canvas");
ctx = canvas.getContext("2d");
anim_img = new Image(size_x, size_y);
anim_img.onload = function()
{
myvar = setInterval(myAnimation, 10);
}
anim_img.src = 'image/download.jpg';
}
function stopMove() {
clearInterval(myVar);
}
function myAnimation() {
ctx.clearRect(0, 0, canvas_size_x, canvas_size_y);
if (x_icon < 0 || x_icon > canvas_size_x - size_x) {stepX = -stepX; }
if (y_icon < 0 || y_icon > canvas_size_y - size_y) {stepY = -stepY; }
x_icon += stepX;
y_icon += stepY;
ctx.drawImage(anim_img, x_icon, y_icon);
}
If you declare your interval (which you call myVar) at the top level of your code (outside of your functions) and also move your nested function out to the top level, you can access both of them as needed, something like:
// Defines global identifiers
let
ctx = null,
x_icon = 0,
y_icon = 0,
stepX = 1,
stepY = 1,
size_x = 260,
size_y = 175,
canvas_size_x = 400,
canvas_size_y = 180,
anim_img = null,
interval = null; // `interval` is a global variable
const
canvas = document.getElementById("canvas"),
button = document.getElementById("button");
// Calls `stop` when the user clicks the button
button.addEventListener("click", stop);
// Calls `draw` immediately to render the initial canvas
draw();
function draw() {
ctx = canvas.getContext("2d");
anim_img = new Image(size_x, size_y);
anim_img.onload = function() {
// Calls `animate` repeatedly until `interval` is cleared
interval = setInterval(animate, 30);
}
anim_img.src = 'https://www.logomaker.com/wp-content/uploads/2018/12/education1.png';
}
function stop() {
clearInterval(interval);
}
function animate() {
// Re-draws the image at different positions on the canvas
ctx.clearRect(0, 0, canvas_size_x, canvas_size_y);
if (x_icon < 0 || x_icon > canvas_size_x - size_x) { stepX *= -1; }
if (y_icon < 0 || y_icon > canvas_size_y - size_y) { stepY *= -1; }
x_icon += stepX;
y_icon += stepY;
ctx.drawImage(anim_img, x_icon, y_icon);
}
<canvas id="canvas" width="400" height="180" style="border:solid 1px;"></canvas>
<button id="button">STOP</button>

Moving multiple object together in canvas with respect to the current position

I have a canvas element with multiple images being displayed. I am trying to achieve is that when I click on a button it should move 200 position in X coordinates. I managed to move the second image, but the first image is not moving. And the images must move with respective to their current position. I am here by attaching my javascript for the same.
$(window).on('load', function () {
imageContent(200);
});
function imageContent(x) {
var posX = x;
var imgArray = ['http://via.placeholder.com/200x200?text=first', 'http://via.placeholder.com/200x200?text=second'];
$.each(imgArray, function (i, l) {
var img = new Image();
img.onload = function () {
var x = 0;
myCanvas(img, i * posX);
};
img.src = l;
});
}
function myCanvas(img, x) {
var c = document.getElementById("myCanvas");
var ctx = c.getContext("2d");
var last_ts = -1
var speed = 0.1
function renderScene() {
ctx.beginPath();
ctx.drawImage(img, x, 0);
}
function fly(ts) {
if (last_ts > 0) {
x += speed * (ts - last_ts)
}
last_ts = ts
if (x < 200) {
imageContent(x);
requestAnimationFrame(fly);
}
}
renderScene();
$('#movebutton').click(function () {
x = 0;
requestAnimationFrame(fly);
});
}
Here is the codepen. It would be greatful if anyone could help me.
Edit: Modified to achieve side by side movement
I modified your code a little, and removed jQuery. See if it is the effect you are trying to achieve:
var imgArr = [],
c = document.getElementById("myCanvas"),
ctx = c.getContext("2d"),
last_ts = -1,
speed = 0.1,
x = 0
window.onload = function() {
[
'http://via.placeholder.com/200x200?text=first',
'http://via.placeholder.com/200x200?text=second'
].forEach(function(obj, idx) {
var img = new Image()
img.onload = function() {
drawImage(img, idx * 200, 0)
}
img.src = obj
imgArr.push(img)
})
}
function drawImages(x) {
ctx.clearRect(0, 0, c.width, c.height)
imgArr.forEach(function(obj, idx) {
drawImage(obj, x + idx*200, 0)
})
}
function drawImage(img, x, y) {
ctx.beginPath()
ctx.drawImage(img, x, y)
}
function fly(ts) {
if (last_ts > 0) {
x += speed * (ts - last_ts)
}
last_ts = ts
if (x < 200) {
drawImages(x)
requestAnimationFrame(fly)
}
}
document
.getElementById('movebutton')
.addEventListener('click', function() {
x = 0
fly()
}, false)
canvas {
border: 1px solid red;
}
<canvas id="myCanvas" width="960" height="600"></canvas>
<button id="movebutton">Move</button>

cache a canvas in an object (in memory)

I am trying to cache the different states a user sets for a canvas,
The thing is that using .push and canvas.clone() when I append it later it's same size, but white; without the image that it was showing,
Any posible way to store a canvas in memory?
-EDIT-
This is how I'm trying
effectosFotos: function ($foto) {
var t;
var selector = '#'+$foto.attr('id');
var $foto = $(selector);
var $backup = $foto.clone();
var times = 0;
var cached = [];
$('.filters').show();
var img1 = document.createElement('img');
img1.onload = function () {
var width1 = $('.filters li').eq(0).width()/3;
var height1 = this.height*(width1/this.width);
console.log(width1, height1);
var canvas1 = document.createElement('canvas'),
ctx1 = canvas1.getContext('2d');
canvas1.width = width1;
canvas1.height = height1;
ctx1.drawImage(this, 0, 0, width1, height1);
var newUrl = canvas1.toDataURL('image/jpeg', 0.8);
$('.filters li a').each(function() {
$(this).append( '<img id="preview_'+$(this).data('id')+'" src="'+newUrl+'">' );
});
$('.filters li a').each(function(i) {
var $this = $(this);
t = setTimeout(function () {
var effect = $this.data('id');
var $img = $('#preview_'+effect);
//console.log('Item='+i +' About to render '+ effect +' and exists? ' + $img.length );
Caman('#preview_'+effect, function () {
this[effect]();
this.render(function(){
//console.log('rendered '+effect);
$this.parent().addClass('rendered');
});
});
}, 1*i)
});
}
img1.src = $foto.attr('src');
$('.filters').on('click', 'li:not(.active) a', function(e){
var start = new Date().getTime();
var $this = $(this).addClass('loading');
$this.parent().addClass('loading');
e.preventDefault();
var effect = $(this).data('id');
var parent = $(selector).parent();
//console.log('f'+$(selector).length, effect,times,$(selector).prop("tagName"),$backup.prop("tagName"));
/*if(times == 0){
$backup = $foto.clone();
}
times++;*/
$(selector).remove();
parent.append($backup);
console.log(cached);
var found = -1;
for ( var c = 0; c < cached.length; c++ ) {
var item = cached[c];
if ( item.effect == effect ) {
found = c;
}
}
if (effect == 'normal'){
$(selector).css('opacity',1);
$this.parent().addClass('active').removeClass('loading').siblings().removeClass('active');
} else if ( found > -1 ) {
console.log('Cargamos caché ' + effect + ' a '+width +'x'+height);
var canvas = document.getElementById($foto.attr('id'))
canvas.width = width;
canvas.height = height;
var ctx3 = canvas.getContext('2d');
ctx3.clearRect( 0, 0, width, height );
ctx3.drawImage( cached[found].canvas, 0, 0);
$this.parent().addClass('active').removeClass('loading').siblings().removeClass('active');
} else {
$(selector).remove();
parent.append($backup);
$(selector).css('opacity',0.3);
$('.takePictureHolder').addClass('caming');
Caman(selector, function () {
this[effect]();
this.render(function(){
$(selector).css('opacity',1);
$this.parent().addClass('active').removeClass('loading').siblings().removeClass('active');
$('.takePictureHolder').removeClass('caming');
if (found == -1) {
var canvas = document.getElementById($foto.attr('id'));
var clone = canvas.cloneNode(true);
clone.getContext('2d').drawImage(canvas, 0,0);
cached.push({ 'effect' :effect, "canvas":clone });
/*var ctx4 = document.getElementById($foto.attr('id')).getContext('2d');
console.log('Cacheamos ' + effect + ' a '+width +'x'+height);
cached.push({ 'effect' :effect, "canvas":ctx4.getImageData(0,0,width, height) });*/
}
var end = new Date().getTime();
var time = end - start;
console.log('Execution time: ' + time);
});
});
}
});
}
The easiest and way more efficient than export methods is to draw your to-be-saved canvas on a clone, using clonedCtx.drawImage(canvas, 0,0). You will then be able to store the cloned canvas in an array :
Andreas' snippet with modified code :
var canvas = document.querySelector("canvas"),
context = canvas.getContext("2d"),
states = [];
console.log('setup states...');
setupState();
function rndColor() {
var rgb = [];
for (var i = 0; i < 3; i++) {
rgb.push(Math.floor(Math.random() * 255));
}
return "rgb(" + rgb.join(",") + ")";
}
function setupState() {
canvas.width = 50 + Math.floor(Math.random() * 100);
canvas.height = 50 + Math.floor(Math.random() * 100);
context.fillStyle = rndColor();
context.fillRect(0, 0, canvas.width, canvas.height);
var clone = canvas.cloneNode(true);
clone.getContext('2d').drawImage(canvas, 0,0);
states.push(clone)
if (states.length < 5) {
setTimeout(setupState, 1000);
} else {
console.log("restore states...");
setTimeout(restoreStates, 2000);
}
}
function restoreStates() {
var state = states.shift();
canvas.width = state.width;
canvas.height = state.height;
context.clearRect(0, 0, state.width, state.height);
context.drawImage(state, 0, 0);
if (states.length) {
setTimeout(restoreStates, 1000);
}
}
canvas { border: solid 5px blue }
<canvas></canvas>
But, as pointed out by #markE, if you need to store a lot of these states (e.g if you want to implement an undo/redo feature), it can quickly fill all your memory.
Then the recommended way is to save all drawing operations and reapply them. Still using Andreas' snippet, a minimal implementation could be :
var canvas = document.querySelector("canvas"),
context = canvas.getContext("2d"),
states = [];
console.log('setup states...');
setupState();
function rndColor() {
var rgb = [];
for (var i = 0; i < 3; i++) {
rgb.push(Math.floor(Math.random() * 255));
}
return "rgb(" + rgb.join(",") + ")";
}
function setupState() {
// create an object with all our states settings and operations
var state = {fillStyle: rndColor(), width: Math.floor(Math.random() * 100), height:Math.floor(Math.random() * 100)};
// save the operations in an array
state.operations = [{name:'fillRect',arguments: [0,0,state.width, state.height]}];
// save the state
states.push(state);
// parse it a first time;
parse(state);
if (states.length < 5) {
setTimeout(setupState, 1000);
} else {
console.log("restore states...");
setTimeout(restoreStates, 2000);
}
}
function parse(state){
// restore our canvas and context's properties
// this could be improved by creating canvas and context objects in our state and then restore the corresponding with a for(x in y) loop
canvas.width = state.width;
canvas.height = state.height;
context.fillStyle = state.fillStyle;
// retrieve the operations we applied
var op = state.operations;
// loop through them
for(var i=0; i<op.length; i++){
// check it actually exists as a function
if(typeof context[op[i].name]==='function')
// apply the saved arguments
context[op[i].name].apply(context, op[i].arguments);
}
}
function restoreStates() {
var state = states.shift();
parse(state);
if (states.length) {
setTimeout(restoreStates, 1000);
}
}
canvas { border: solid 1px blue }
<canvas></canvas>
You could save the content of the canvas with .getImageData().
And .putImageData() for restoring the old content.
var data = [];
// store canvas/image
data.push(context.getImageData(0, 0, canvas.width, canvas.height));
// restore canvas/image
var oldData = data.pop();
canvas.width = oldData.width;
canvas.height = oldData.height;
context.clearRect(oldData, 0, 0, canvas.width, canvas.height);
context.putImageData(oldData, 0, 0);
var canvas = document.querySelector("canvas"),
context = canvas.getContext("2d"),
states = [],
img;
console.log("setup states...");
setupState();
function rndColor() {
var rgb = [];
for (var i = 0; i < 3; i++) {
rgb.push(Math.floor(Math.random() * 255));
}
return "rgb(" + rgb.join(",") + ")";
}
function setupState() {
canvas.width = 50 + Math.floor(Math.random() * 100);
canvas.height = 50 + Math.floor(Math.random() * 100);
context.fillStyle = rndColor();
context.fillRect(0, 0, canvas.width, canvas.height);
states.push(context.getImageData(0, 0, canvas.width, canvas.height));
if (states.length < 5) {
setTimeout(setupState, 1000);
} else {
console.log("restore states...");
setTimeout(restoreStates, 2000);
}
}
function restoreStates() {
var state = states.shift();
canvas.width = state.width;
canvas.height = state.height;
context.clearRect(0, 0, state.width, state.height);
context.putImageData(state, 0, 0);
if (states.length) {
setTimeout(restoreStates, 1000);
}
}
canvas { border: solid 5px blue }
<canvas></canvas>
The same would be possible with .toDataUrl()
and .drawImage()
But this would be the slower approach: jsperf (at least in chrome)
var images = [];
// store canvas/image
var img = new Image();
img.src = canvas.toDataURL();
images.push(img);
// restore canvas/image
var oldImage = images.pop();
canvas.width = oldImage.width;
canvas.height = oldImage.height;
context.clearRect(0, 0, canvas.width, canvas.height);
context.drawImage(oldImage, 0, 0);
var canvas = document.querySelector("canvas"),
context = canvas.getContext("2d"),
states = [],
img;
console.log("setup states...");
setupState();
function rndColor() {
var rgb = [];
for (var i = 0; i < 3; i++) {
rgb.push(Math.floor(Math.random() * 255));
}
return "rgb(" + rgb.join(",") + ")";
}
function setupState() {
canvas.width = 50 + Math.floor(Math.random() * 100);
canvas.height = 50 + Math.floor(Math.random() * 100);
context.fillStyle = rndColor();
context.fillRect(0, 0, canvas.width, canvas.height);
img = new Image();
img.src = canvas.toDataURL();
states.push(img);
if (states.length < 5) {
setTimeout(setupState, 1000);
} else {
console.log("restore states...");
setTimeout(restoreStates, 2000);
}
}
function restoreStates() {
var state = states.shift();
canvas.width = state.width;
canvas.height = state.height;
context.clearRect(0, 0, canvas.width, canvas.height);
context.drawImage(state, 0, 0);
if (states.length) {
setTimeout(restoreStates, 1000);
}
}
canvas { border: solid 5px blue }
<canvas></canvas>

HTML5 Canvas blinking on drawing

I'm beginning with an isometric game, and my canvas is blinking(Not in IE) when draws all the parts of the ground. When I set fps to 20 or less, the blinking stops. How can I solve that? Any ideas?
var camerax = 300, cameray = 100;
var fps = 60;
function draw() {
clearCanvas();
drawGround();
}
function drawGround() {
var img = new Image();
img.onload = function() {
var width = img.width;
var height = img.height;
for (var x = 0; x < 3; x++) {
for (var y = 3; y >= 0; y--) {
mx = (x-y)*height + camerax;
my = (x+y)*height/2 + cameray;
ctx.drawImage(img, mx, my);
}
}
}
img.src = "ground.png";
}
var loop = setInterval(function() {
update();
draw();
}, 1000/fps);
Right now you're reloading the image every frame and unless the onload callback fires within the 16ms of the frame you're going to see a blank canvas.
You should only need to call the new Image, img.onload sequence once, to preload your images. The onload callback would then kick off your first frame, and the draw calls are free to use the image in memory.
Something like:
var camerax = 300, cameray = 100;
var fps = 60;
var img;
var loop;
function init() {
img = new Image();
img.onload = function() {
loop = setInterval(function() {
update();
draw();
}, 1000/fps);
};
img.src = "ground.png";
}
function draw() {
clearCanvas();
drawGround();
}
function drawGround() {
var width = img.width;
var height = img.height;
for (var x = 0; x < 3; x++) {
for (var y = 3; y >= 0; y--) {
mx = (x-y)*height + camerax;
my = (x+y)*height/2 + cameray;
ctx.drawImage(img, mx, my);
}
}
}
}
Of course, it gets more complex once you're waiting for multiple images to preload since you need to start the loop only once all of them are done.
Nice tip, freejosh! Thanks! My screen now is not blinking and the code result was that:
var canvas = document.getElementById("game");
var ctx = canvas.getContext("2d");
var camerax = 300, cameray = 100;
var fps = 60;
var img;
var loop;
function update() {
}
function draw() {
clearCanvas();
drawGround();
}
function clearCanvas() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
}
function drawGround() {
var width = img.width;
var height = img.height;
for (var x = 0; x < 3; x++) {
for (var y = 3; y >= 0; y--) {
mx = (x-y)*height + camerax;
my = (x+y)*height/2 + cameray;
ctx.drawImage(img, mx, my);
}
}
}
function init() {
img = new Image();
img.onload = function() {
drawGround();
};
img.src = "ground.png";
}
function keyListener(e){
e = e || window.event
if(e.keyCode==37){
camerax--;
}
else if(e.keyCode==39){
camerax++;
}
else if(e.keyCode==38){
cameray--;
}
else if(e.keyCode==40){
cameray++;
}
}
window.onkeypress = function(e) {
keyListener(e);
}
init();
var loop = setInterval(function() {
update();
draw();
}, 1000/fps);

Categories

Resources