JavaScript: Constantly Switch image source - javascript

My end goal is pretty simple. Once a page loads, I want an image to appear, but I want it to be constantly switching. (Ultimately, to make a fish look like it's bobbing up and down).
Right now my code looks like this:
var myFish = new Image();
var canvas = document.getElementById('myCanvas');
var context = canvas.getContext('2d');
myFish.onload = function(){
context.drawImage(myFish, 100, 30, 200, 137);
};
myFish.src = "img/fish.png";
I'm not using JQuery, just straight javascript. How could I constantly switch back and forth between this image, and another image saved in the same directory.
Thank you!

You'll need to use the timer functions
function updateImageSrcHere()
{
//Update Image src
}
//Interval is measured in MS so 1000 = 1 second
var interval = 1000;
setInterval(updateImageSrcHere, interval);

Related

Using `jsgif` to build layers over animated GIFs

I'm looking to get some help or guidance on the use of the excellent libgif.js library.
My objective is to take a page that has an animated gif and a png of text with transparent background, and then show the 2 images overlaid such that the resulting image can be copied to the clipboard.
I've succeeded in doing this with a static image as a template
However, if I try this with a gif, it merges the animated gif with the text image, but freezes the gif.
I've familiarized myself with the libgif.js library and have succeeded in using it to build a canvas from an animated gif and have it remain animated.
However, the text image is not being displayed in the final canvas, and I'm a little lost as to how I might go about fixing this.
Is it obvious to anyone why the textImage is being properly sized and (somewhat) apparently placed on the canvas, but not displayed in the final result?
As a side question, does anyone know why the progress bar completes quickly at first and then progresses more slowly a second time?
The HTML is rather long, but the JS from the JSFiddle is shown below (for those not willing to click through to the link).
function doit() {
var isGIF = true; // always true for now TODO: better way to test if-gif than regex for ".gif"
var previewContainer = document.getElementById("previewContainer");
var textImage = document.getElementById("textImage");
var templateImage = document.getElementById("templateImage");
var w = document.getElementById("templateImage").width;
var h = document.getElementById("templateImage").height;
previewContainer.removeChild(previewContainer.children[1]);
if (isGIF) {
var gif = new SuperGif({
gif: templateImage,
progressbar_height: 5,
auto_play: true,
loop_mode: true,
draw_while_loading: true
});
gif.load();
var canvas = gif.get_canvas();
var context = canvas.getContext('2d');
context.drawImage(textImage, 0, 0, w, h);
previewContainer.replaceChild(canvas, previewContainer.children[0]);
}
}
Note: this solution was originally based on Arend's solution in the comments of this question from this JSFiddle.
You would have to tweak the library in order to get access to their rendering loop (like a frame_rendered event).
This way, you would be able to add whatever you want over the image the library drawn at every frame.
But since I'm too lazy to dig in there, here is a workaround :
Instead of appending the canvas returned by the library in the document, you can keep it offscreen, and draw it on an other, visible, canvas.
It is on this new canvas that you will also draw your textImage, in an rAF loop.
function doit() {
var previewContainer = document.getElementById("previewContainer");
var textImage = document.getElementById("textImage");
var templateImage = document.getElementById("templateImage");
var w = templateImage.width;
var h = templateImage.height;
previewContainer.removeChild(previewContainer.children[1]);
var gif = new SuperGif({
gif: templateImage,
progressbar_height: 5,
auto_play: true,
loop_mode: true,
draw_while_loading: true
});
gif.load();
var gif_canvas = gif.get_canvas(); // the lib canvas
// a copy of this canvas which will be appended to the doc
var canvas = gif_canvas.cloneNode();
var context = canvas.getContext('2d');
function anim(t) { // our animation loop
context.clearRect(0,0,canvas.width,canvas.height); // in case of transparency ?
context.drawImage(gif_canvas, 0, 0); // draw the gif frame
context.drawImage(textImage, 0, 0, w, h); // then the text
requestAnimationFrame(anim);
};
anim();
previewContainer.replaceChild(canvas, previewContainer.children[0]);
}
<script src="https://cdn.rawgit.com/buzzfeed/libgif-js/master/libgif.js"></script>
<div>
<input type="submit" id="doit" value="Do it!" onclick="doit()" />
</div>
<div id="previewContainer">
<img id="templateImage" src="https://i.imgur.com/chWt4Yg.gif" />
<img id="textImage" src="https://i.stack.imgur.com/CmErq.png" />
</div>

Firefox drawing blank Canvas when restoring from saved base64

I am working with a single canvas that allows the user to click on a window pane in a window image. The idea is to show where the user has clicked. The image will then be modified (by drawing a grill on the window) and then saved to in JPEG. I am saving the canvas image prior to the click function because I don't want the selection box to show in the final image. However, Firefox often displays a blank canvas when restoring the canvas where IE and Chrome do not. This works perfectly in Chrome and IE. Any suggestions? Does Firefox have a problem with toDataURL()? Maybe some async issue going on here? I am also aware that saving a canvas in this fashion is memory intensive and there may be a better way to do this but I'm working with what I have.
Code:
/**
* Restores canvas from drawingView.canvasRestorePoint if there are any restores saved
*/
restoreCanvas:function()
{
var inverseScale = (1/drawingView.scaleFactor);
var canvas = document.getElementById("drawPop.canvasOne");
var c = canvas.getContext("2d");
if (drawingView.canvasRestorePoint[0]!=null)
{
c.clearRect(0,0,canvas.width,canvas.height);
var img = new Image();
img.src = drawingView.canvasRestorePoint.pop();
c.scale(inverseScale,inverseScale);
c.drawImage(img, 0, 0);
c.scale(drawingView.scaleFactor, drawingView.scaleFactor);
}
},
/**
* Pushes canvas into drawingView.canvasRestorePoint
*/
saveCanvas:function()
{
var canvas = document.getElementById("drawPop.canvasOne");
var urlData = canvas.toDataURL();
drawingView.canvasRestorePoint.push(urlData);
},
EXAMPLE OF USE:
readGrillInputs:function()
{
var glassNum = ir.get("drawPop.grillGlassNum").value;
var panelNum = ir.get("drawPop.grillPanelNum").value;
drawingView.restoreCanvas();
drawEngine.drawGrill(glassNum, panelNum,null);
drawingView.saveCanvas();
},
sortClick:function(event)
{
..... //Sorts where user has clicked and generates panel/glass num
.....
drawingView.showClick(panelNum, glassNum);
},
showClick:function(panelNum, glassNum)
{
var glass = item.panels[panelNum].glasses[glassNum];
var c = drawEngine.context;
drawingView.restoreCanvas();
drawingView.saveCanvas();
c.strokeStyle = "red";
c.strokeRect(glass.x, glass.y, glass.w, glass.h);
},
By just looking at the code setting the img.src is an async action to retrieve the image, so when you try to draw it 2 lines later to the canvas, it probably hasn't been loaded yet (having it in cache will make it return fast enough that it might work).
You should instead use an img.onload function to draw the image when it has loaded.
restoreCanvas:function()
{
var inverseScale = (1/drawingView.scaleFactor);
var canvas = document.getElementById("drawPop.canvasOne");
var c = canvas.getContext("2d");
if (drawingView.canvasRestorePoint[0]!=null)
{
c.clearRect(0,0,canvas.width,canvas.height);
var img = new Image();
img.onload = function() {
c.scale(inverseScale,inverseScale);
c.drawImage(img, 0, 0);
c.scale(drawingView.scaleFactor, drawingView.scaleFactor);
};
img.src = drawingView.canvasRestorePoint.pop();
}
},

Why JavaScript code execute second part sometimes

I am draw background on canvas and also small images on that background. But sometimes, background draw on small images. Why ?
JavaScript code -
var canvasupdate = document.getElementById("myCanvas");
ctxupdate = canvasupdate.getContext("2d");
var background = new Image();
background.src = sitePath + "ATOM/chapter1/book/" + `bgimagename`;
background.onload = function() {
ctxupdate.drawImage(background, 0, 0); // set background image
};
var imageobj = new Array();
for (var d = 0; d < calloutImageArray.length; d++) // getting small images in array
{
imageobj[d] = new Image();
(function(d) {
imageobj[d].src = sitePath + "ATOM/chapter1/book/" + calloutImageArray[d];
imageobj[d].onload = function() {
ctxupdate.drawImage(imageobj[d], calloutImageArrayX[d], calloutImageArrayY[d], calloutImageArrayW[d], calloutImageArrayH[d]);
};
})(d);
}
In above code, background image code should be execute first then call out image(small image) code execute but some time execute small images code and then background image code why?
All the images are loaded asynchronously. So sometimes the small images are loaded (and drawn) before the background image. Please take a look into e.g. Network tab in Chrome in which order the resources load is done.
The simplest solution for this problem is to move the loading of small images into the callback function for load event of the background image.
The onLoad function runs asynchronously. That means JavaScript will continue to run the rest of your code and will run the callback function when the background image is loaded. That's why your second part of the code runs first. So instead try to add your code inside the onload function like this:
var canvasupdate = document.getElementById("myCanvas");
ctxupdate = canvasupdate.getContext("2d");
var background = new Image();
background.src = sitePath + "ATOM/chapter1/book/" + `bgimagename`;
background.onload = function() {
ctxupdate.drawImage(background, 0, 0); // set background image
var imageobj = new Array();
for (var d = 0; d < calloutImageArray.length; d++) // getting small images in array
{
imageobj[d] = new Image();
(function(d) {
imageobj[d].src = sitePath + "ATOM/chapter1/book/" + calloutImageArray[d];
imageobj[d].onload = function() {
ctxupdate.drawImage(imageobj[d], calloutImageArrayX[d], calloutImageArrayY[d], calloutImageArrayW[d], calloutImageArrayH[d]);
};
})(d);
}
};
that way you can be sure that the background will be set first and then your small images. Note that I didn't try your code to check if it does what you want, I just rearranged the code blocks to show you the logic and why does not run as you would expect.
Hope it helps

Spine multiple animations

So I have 2, or more skeletons for an animation (so, 2 or more json files). I want them to play at the same time and 10 seconds after, to play another animation.
Problem is that there is only one animation playing, and the second isn't displayed.
The way I'm doing it is the following:
<canvas id="animationCanvas" width="240" height="240"></canvas>
<script>
var first = true,
rendererFirst = new spine.SkeletonRenderer('http://someurl.com/images/'),
spineAFirst = /* My JSON Code */,
parsedFirst = JSON.parse(spineAFirst);
rendererFirst.scale = 0.2;
rendererFirst.load(spineAFirst);
rendererFirst.state.data.defaultMix = 1.0;
for (var i in parsedFirst.animations) {
if (first) {
first = false;
rendererFirst.state.setAnimationByName(0, i, true);
} else {
rendererFirst.state.addAnimationByName(0, i, true, 10);
}
}
rendererFirst.skeleton.x = 120;
rendererFirst.skeleton.y = 120;
rendererFirst.animate('animationCanvas');
</script>
And, of course, I'm doing it twice (or more). I tried as well with a single SkeletonRenderer, just loading (and setting or adding) animations as many times as I need, and it didn't worked.
It seems that the renderer is cleaning the canvas each time it is called, the better way to achieve this seems to create a canvas for each animation, and bind a renderer to each one.

jQuery and Canvas loading behaviour

After being a long time lurker, this is my first post here! I've been RTFMing and searching everywhere for an answer to this question to no avail. I will try to be as informative as I can, hope you could help me.
This code is for my personal webpage.
I am trying to implement some sort of a modern click-map using HTML5 and jQuery.
In the website you would see the main image and a hidden canvas with the same size at the same coordinates with this picture drawn into it.
When the mouse hovers the main picture, it read the mouse pixel data (array of r,g,b,alpha) from the image drawn onto the canvas. When it sees the pixel color is black (in my case I only check the RED value, which in a black pixel would be 0) it knows the activate the relevant button.
(Originally, I got the idea from this article)
The reason I chose this method, is for the page to be responsive and dynamically change to fit different monitors and mobile devices. To achieve this, I call the DrawCanvas function every time the screen is re-sized, to redraw the canvas with the new dimensions.
Generally, this works OK. The thing is ,there seems to be an inconsistent behavior in Chrome and IE(9). When I initially open the page, I sometimes get no pixel data (0,0,0,0), until i re-size the browser. At first I figured there's some loading issues that are making this happen so I tried to hack it with setTimeout, it still doesn't work. I also tried to trigger the re-size event and call the drawCanvas function at document.ready, still didn't work.
What's bothering me is most, are the inconsistencies. Sometimes it works, sometimes is doesn't. Generally, it is more stable in chrome than in IE(9).
Here is the deprecated code:
<script type="text/javascript">
$(document).ready(function(){setTimeout(function() {
// Get main image object
var mapWrapper = document.getElementById('map_wrapper').getElementsByTagName('img').item(0);
// Create a hidden canvas the same size as the main image and append it to main div
var canvas = document.createElement('canvas');
canvas.height = mapWrapper.clientHeight;
canvas.width = mapWrapper.clientWidth;
canvas.fillStyle = 'rgb(255,255,255)';
canvas.style.display = 'none';
canvas.id = 'hiddencvs';
$('#map_wrapper').append(canvas);
// Draw the buttons image into the canvas
drawCanvas(null);
$("#map_wrapper").mousemove(function(e){
var canvas = document.getElementById('hiddencvs');
var context = canvas.getContext('2d');
var pos = findPos(this);
var x = e.pageX - pos.x;
var y = e.pageY - pos.y;
// Get pixel information array (red, green, blue, alpha)
var pixel = context.getImageData(x,y,1,1).data;
var red = pixel[0];
var main_img = document.getElementById('map_wrapper').getElementsByTagName('img').item(0);
if (red == 0)
{
...
}
else {
...
}
});
},3000);}); // End DOM Ready
function drawCanvas(e)
{
// Get context of hidden convas and set size according to main image
var cvs = document.getElementById('hiddencvs');
var ctx = cvs.getContext('2d');
var mapWrapper = document.getElementById('map_wrapper').getElementsByTagName('img').item(0);
cvs.width = mapWrapper.clientWidth;
cvs.height = mapWrapper.clientHeight;
// Create img element for buttons image
var img = document.createElement("img");
img.src = "img/main-page-buttons.png";
// Draw buttons image inside hidden canvas, strech it to canvas size
ctx.drawImage(img, 0, 0,cvs.width,cvs.height);
}
$(window).resize(function(e){
drawCanvas(e);
}
);
function findPos(obj)
{
...
}
</script>
I'd appreciate any help!
Thanks!
Ron.
You don't wait for the image to be loaded so, depending on the cache, you may draw an image or not in the canvas.
You should do this :
$(function(){
var img = document.createElement("img");
img.onload = function() {
var mapWrapper = document.getElementById('map_wrapper').getElementsByTagName('img').item(0);
...
// your whole code here !
...
}
img.src = "img/main-page-buttons.png";
});

Categories

Resources