This question about crossfading images already gave an answer to the crossfading solution in Canvas. I am trying to do the same thing, only difference is that i am trying to fade images that are loaded on runtime.
The images are loaded propperly but no fade is visible. Is this not working because of the loaded images? Thanks.
HTML
<div id="wrapper">
<canvas id="bg1"></canvas>
<canvas id="bg2"></canvas>
</div>
JS
var toggle = true;
var canvas = document.getElementById('bg1');
canvas.width = $(document).width();
canvas.height = $(document).height();
var ctx = canvas.getContext('2d');
var canvas2 = document.getElementById('bg2');
canvas2.width = $(document).width();
canvas2.height = $(document).height();
var ctx2 = canvas2.getContext('2d');
var image = new Image();
image.src = 'download1.jpg';
var image2 = new Image();
image2.src = 'download2.jpg';
image.onload = function() {
ctx.drawImage(image, 0, 0, 200, 100);
ctx2.drawImage(image2, 0, 0, 200, 100);
};
$('#wrapper').click(function () {
if (toggle)
{
$('#bg2').fadeIn();
$('#bg1').fadeOut();
}
else
{
$('#bg1').fadeIn();
$('#bg2').fadeOut();
}
toggle = !toggle;
});
Yep, you need to give your images time to load.
But also, jQuery cannot do fadeIn/fadeout on a canvas element so you will have to do that manually.
Demo: http://jsfiddle.net/m1erickson/zw9S4/
Code:
<!doctype html>
<html>
<head>
<link rel="stylesheet" type="text/css" media="all" href="css/reset.css" /> <!-- reset css -->
<script type="text/javascript" src="http://code.jquery.com/jquery.min.js"></script>
<style>
body{ background-color: ivory; }
canvas{border:1px solid red;}
</style>
<script>
$(function(){
$("#fade").hide();
var imageURLs=[]; // put the paths to your images here
var imagesOK=0;
var imgs=[];
imageURLs.push("https://dl.dropboxusercontent.com/u/139992952/stackoverflow/house204-1.jpg");
imageURLs.push("https://dl.dropboxusercontent.com/u/139992952/stackoverflow/house204-2.jpg");
imageURLs.push("https://dl.dropboxusercontent.com/u/139992952/stackoverflow/house204-3.jpg");
imageURLs.push("https://dl.dropboxusercontent.com/u/139992952/stackoverflow/house204-4.jpg");
loadAllImages();
//
function loadAllImages(){
for (var i=0; i<imageURLs.length; i++) {
var img = new Image();
imgs.push(img);
img.onload = function(){
imagesOK++;
if (imagesOK>=imageURLs.length ) {
$("#fade").show();
ctx.drawImage(imgs[0],0,0);
}
};
img.onerror=function(){alert("image load failed");}
img.crossOrigin="anonymous";
img.src = imageURLs[i];
}
}
var canvas=document.getElementById("canvas");
var ctx=canvas.getContext("2d");
var fadeOutIndex=imgs.length-1;
var fadeInIndex=0;
var fadePct=0;
function animateFade(){
if(fadePct>100){return;}
requestAnimationFrame(animateFade);
ctx.clearRect(0,0,canvas.width,canvas.height);
draw(imgs[fadeInIndex],fadePct/100);
draw(imgs[fadeOutIndex],(1-fadePct/100));
fadePct++;
}
function draw(img,opacity){
ctx.save();
ctx.globalAlpha=opacity;
ctx.drawImage(img,0,0);
ctx.restore();
}
$("#fade").click(function(){
fadePct=0;
if(++fadeOutIndex == imgs.length){fadeOutIndex=0;}
if(++fadeInIndex == imgs.length){fadeInIndex=0;}
animateFade();
});
}); // end $(function(){});
</script>
</head>
<body>
<button id="fade">Fade to next Image</button><br>
<canvas id="canvas" width=204 height=204></canvas><br>
</body>
</html>
Try to fade in/out the images directly on the canvas instead of fading in and out the canvas elements (or there is not really any point using the canvas as you could use image elements instead).
First, of course, wait for the images to load:
var isBusy = false, /// for fade loop
count = 2; /// number of images to load
image = new Image();
image2 = new Image();
/// setup load handler
image.onload = image2.onload = handleLoad;
image.src = 'download1.jpg';
image2.src = 'download2.jpg';
function handleLoad() {
count--;
if (count === 0) {
/// when loaded draw a single image onto canvas
ctx.drawImage(image, 0, 0, ctx.canvas.width, ctx.canvas.height);
}
};
Now we can change the click handler a little bit around and use canvas only to do the fade in of the next image:
$('#wrapper').click(function () {
var img, /// current image to fade in
opacity = 0; /// current globalAlpha of canvas
/// if we're in a fade exit until done
if (isBusy) return;
isBusy = true;
/// what image to use
img = toggle ? image2 : image;
/// fade in
(function fadeIn() {
/// set alpha
ctx.globalAlpha = opacity;
/// draw image with current alpha
ctx.drawImage(img, 0, 0, ctx.canvas.width, ctx.canvas.height);
/// increase alpha to 1, then exit resetting isBusy flag
opacity += 0.02;
if (opacity < 1)
requestAnimationFrame(fadeIn);
else
isBusy = false;
})();
toggle = !toggle;
});
Online demo
Hope this helps.
Related
PS: Is it not a research kind of question! I have been trying to do this from very long time.
I am trying to make web based an image editor where user can select multiple cropping area and after selection save/download all the image area. like below.
As of now I discovered two libraries
1.Cropper.JS where is only single selection feature is available.
2.Jcrop where only single selection area restrictions.
I am currently using cropper.Js but it seems impossible for me to make multiple selection cropping.
Any help is much appreciated.if any other method/library available in JavaScript, Angular or PHP or reactJS for multiple image area selection and crop and download in one go as in the image below.
As per #Keyhan Answer I am Updating my Jcrop library Code
<div style="padding:0 5%;">
<img id="target" src="https://d3o1694hluedf9.cloudfront.net/market-750.jpg">
</div>
<button id="save">Crop it!</button>
<link rel="stylesheet" href="https://unpkg.com/jcrop/dist/jcrop.css">
<script src="https://unpkg.com/jcrop"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
JavaScript
<script>
setImage();
var jcp;
var jcp;
Jcrop.load('target').then(img => {
//You can enable multiple cropping with this line:
jcp = Jcrop.attach(img, { multi: true });
});
// to fix security issue when trying to convert to Data URI
function setImage() {
document.getElementById('target').setAttribute('crossOrigin', 'anonymous');
document.getElementById('target').src = 'https://d3o1694hluedf9.cloudfront.net/market-750.jpg';
}
var link = document.getElementById('save');
link.onclick = function () {
//we check if at least one crop is available
if (jcp.active) {
var i = 0;
var fullImg = document.getElementById("target");
//we are looping cropped areas
for (area of jcp.crops) {
i++;
//creating temp canvas and drawing cropped area on it
canvas = document.createElement("canvas");
canvas.setAttribute('width', area.pos.w);
canvas.setAttribute('height', area.pos.h);
ctx = canvas.getContext("2d");
ctx.drawImage(fullImg, area.pos.x, area.pos.y, area.pos.w, area.pos.h, 0, 0, area.pos.w, area.pos.h);
//creating temp link for saving/serving new image
temp = document.createElement('a');
temp.setAttribute('download', 'area' + i + '.jpg');
temp.setAttribute('href', canvas.toDataURL("image/jpg").replace("image/jpg", "image/octet-stream"));
temp.click();
}
}
};
</script>
I tried to explain the code with comments:
var jcp;
Jcrop.load('target').then(img => {
//You can enable multiple cropping with this line:
jcp = Jcrop.attach(img,{multi:true});
});
//assuming you have a button with id="save" for exporting cropped areas
var link=document.getElementById('save');
link.onclick = function(){
//we check if at least one crop is available
if(jcp.active){
var i=0;
var fullImg = document.getElementById("target");
//we are looping cropped areas
for(area of jcp.crops){
i++;
//creating temp canvas and drawing cropped area on it
canvas = document.createElement("canvas");
canvas.setAttribute('width',area.pos.w);
canvas.setAttribute('height',area.pos.h);
ctx = canvas.getContext("2d");
ctx.drawImage(fullImg, area.pos.x, area.pos.y, area.pos.w, area.pos.h, 0, 0, area.pos.w, area.pos.h);
//creating temp link for saving/serving new image
temp = document.createElement('a');
temp.setAttribute('download', 'area'+i+'.jpg');
temp.setAttribute('href', canvas.toDataURL("image/jpg").replace("image/jpg", "image/octet-stream"));
temp.click();
}
}
};
EDIT: As you commented it would be nicer if we have local image loader, we can add a file input to our html
<img id="target" />
<br/>
<input type="file" id="imageLoader" name="imageLoader"/><!-- add this for file picker -->
<button id="save">save</button>
and a function to our js to handle it
var jcp;
var save=document.getElementById('save');
var imageLoader = document.getElementById('imageLoader');
var img = document.getElementById("target");
imageLoader.onchange=function handleImage(e){//handling our image picker <input>:
var reader = new FileReader();
reader.onload = function(event){
img.src = event.target.result;
}
reader.readAsDataURL(e.target.files[0]);
}
save.onclick = function(){
if(jcp&&jcp.active){
var i=0;
for(area of jcp.crops){
i++;
canvas = document.createElement("canvas");
canvas.setAttribute('width',area.pos.w);
canvas.setAttribute('height',area.pos.h);
ctx = canvas.getContext("2d");
ctx.drawImage(img, area.pos.x, area.pos.y, area.pos.w, area.pos.h, 0, 0, area.pos.w, area.pos.h);
temp = document.createElement('a');
temp.setAttribute('download', 'area'+i+'.jpg');
temp.setAttribute('href', canvas.toDataURL("image/jpg").replace("image/jpg", "image/octet-stream"));
temp.click();
}
}
};
Jcrop.load('target').then(img => {
jcp = Jcrop.attach(img,{multi:true});
});
Yes, #keyhan was right <input type="file"> is another question, but still, I am giving you an idea of how to implement Kayhan's code above.
<div>
<input type="file" id="image-input" accept="image/*">
<!-- img id name should be "target" as it is also using by Jcrop -->
<img id="target"></img>
</div>
and Now you can put below JavaScript Code just above setImage()
<script>
let imgInput = document.getElementById('image-input');
imgInput.addEventListener('change', function (e) {
if (e.target.files) {
let imageFile = e.target.files[0];
var reader = new FileReader();
reader.onload = function (e) {
var img = document.createElement("img");
img.onload = function (event) {
var MAX_WIDTH = 1600;
var MAX_HEIGHT = 800;
var width = img.width;
var height = img.height;
// Change the resizing logic
if (width > height) {
if (width > MAX_WIDTH) {
height = height * (MAX_WIDTH / width);
width = MAX_WIDTH;
}
} else {
if (height > MAX_HEIGHT) {
width = width * (MAX_HEIGHT / height);
height = MAX_HEIGHT;
}
}
// Dynamically create a canvas element
var canvas = document.createElement("canvas");
canvas.width = width;
canvas.height = height;
// var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
// Actual resizing
ctx.drawImage(img, 0, 0, width, height);
// Show resized image in preview element
var dataurl = canvas.toDataURL(imageFile.type);
document.getElementById("target").src = dataurl;
}
img.src = e.target.result;
}
reader.readAsDataURL(imageFile);
}
});
</script>
I have an issue I'm having a hard time believing... It seems that when I draw to a dynamically created canvas in Firefox it wont render the first time that source is run... It seems to happen the first time the JavaScript in question is run either by modifying the source or visiting the link for the first time. Here are some repro steps:
1) open a brand new instance of Firefox. visit the jsFiddle below.
2) see nothing
3) open a new tab in Firefox. visit the jsFiddle below.
4) see the result (10 colored squares)
Doing this in Chrome will result in seeing the result at both step 2 and step 4.
https://jsfiddle.net/sk873txv/1/
html
<body>
<div id="a">
</div>
</body>
js
$(document).ready(function(){
var make_canvas = function(i) {
var $canvas = $('<canvas>').appendTo($('#a'));
$canvas.attr('width', '100px');
$canvas.attr('height', '100px');
var canvas = $canvas[0];
var ctx = canvas.getContext('2d');
return ctx;
};
var draw = function(ctx) {
var image = new Image();
image.src = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGQAAABkEAIAAACvEN5AAAAABmJLR0T///////8JWPfcAAAACXBIWXMAAABIAAAASABGyWs+AAABa0lEQVR42u3cMU4CARRF0SeyWl0P7FaxoKbBuRrNOZUJCU7xcv9UvGzb7Xa6btvrddse/f2dT0+Xg77noOd58r9c/tTTPvr08hPPc962z7fBoc7b9mFYHEyxSCgWCcUioVgkDIuEU0hCsUgoFgnFImFYJJxCEopFQrFIKBaJe7Hef/sx+G8Ui4RhkfDyTkKxSCgWCcUiYVgknEISikVCsUgoFgnFIqFYJAyLhFNIQrFIKBYJxSJhWCScQhKKRUKxSCgWCcMi4RSSUCwSikVCsUgoFgnFImFYJJxCEvdi+eE1DqZYJLxjkTAsEk4hCcUioVgkFIuEYpFQLBKGRcIpJKFYJBSLhGKRMCwSTiEJxSKhWCQUi4RhkXAKSSgWCcUioVgkFIuEYpEwLBJOIQnFIqFYJBSLhGGRuJ9CP7zGwRSLhJd3EopFQrFIKBYJwyLhFJJQLBKKRUKxSBgWCaeQhGKRUCwSikVCsUh8ARsPyYz6AmddAAAAJXRFWHRkYXRlOmNyZWF0ZQAyMDExLTA0LTA3VDIxOjM2OjAyKzEwOjAwezv9bwAAACV0RVh0ZGF0ZTptb2RpZnkAMjAxMS0wNC0wN1QyMTozNjowMisxMDowMApmRdMAAAA2dEVYdFBORzpiS0dEAGNodW5rIHdhcyBmb3VuZCAoc2VlIEJhY2tncm91bmQgY29sb3IsIGFib3ZlKbpeXNkAAAAVdEVYdFBORzpJSERSLmJpdF9kZXB0aAAxNqc4FdcAAAAVdEVYdFBORzpJSERSLmNvbG9yX3R5cGUAMgEnYzIAAAAbdEVYdFBORzpJSERSLmludGVybGFjZV9tZXRob2QAMPs7B4wAAAAedEVYdFBORzpJSERSLndpZHRoLGhlaWdodAAxMDAsIDEwMNtVy6kAAAAkdEVYdFBORzpwSFlzAHhfcmVzPTcyLCB5X3Jlcz03MiwgdW5pdHM9MKQw/n0AAAArdEVYdFBORzp0ZXh0ADIgdEVYdC96VFh0L2lUWHQgY2h1bmtzIHdlcmUgZm91bmRcYYD5AAAAAElFTkSuQmCC";
ctx.drawImage(image, 0, 0);
};
for(var i = 0; i < 10; i++)
{
draw(make_canvas(i));
}
});
You should wait for the load event to fire on the image, before drawing it to a canvas. Even though the image data is embedded as a data URI, there is no guarantee the image will be rendered and ready to draw the instant you set the src. Waiting for the load event will ensure the image is ready.
Working Example (JSFiddle):
$(document).ready(function(){
var make_canvas = function(i) {
var $canvas = $('<canvas>').appendTo($('#a'));
$canvas.attr('width', '100px');
$canvas.attr('height', '100px');
var canvas = $canvas[0];
var ctx = canvas.getContext('2d');
return ctx;
};
var draw = function(ctx) {
var image = new Image();
image.onload = function() {
ctx.drawImage(image, 0, 0);
};
image.src = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGQAAABkEAIAAACvEN5AAAAABmJLR0T///////8JWPfcAAAACXBIWXMAAABIAAAASABGyWs+AAABa0lEQVR42u3cMU4CARRF0SeyWl0P7FaxoKbBuRrNOZUJCU7xcv9UvGzb7Xa6btvrddse/f2dT0+Xg77noOd58r9c/tTTPvr08hPPc962z7fBoc7b9mFYHEyxSCgWCcUioVgkDIuEU0hCsUgoFgnFImFYJJxCEopFQrFIKBaJe7Hef/sx+G8Ui4RhkfDyTkKxSCgWCcUiYVgknEISikVCsUgoFgnFIqFYJAyLhFNIQrFIKBYJxSJhWCScQhKKRUKxSCgWCcMi4RSSUCwSikVCsUgoFgnFImFYJJxCEvdi+eE1DqZYJLxjkTAsEk4hCcUioVgkFIuEYpFQLBKGRcIpJKFYJBSLhGKRMCwSTiEJxSKhWCQUi4RhkXAKSSgWCcUioVgkFIuEYpEwLBJOIQnFIqFYJBSLhGGRuJ9CP7zGwRSLhJd3EopFQrFIKBYJwyLhFJJQLBKKRUKxSBgWCaeQhGKRUCwSikVCsUh8ARsPyYz6AmddAAAAJXRFWHRkYXRlOmNyZWF0ZQAyMDExLTA0LTA3VDIxOjM2OjAyKzEwOjAwezv9bwAAACV0RVh0ZGF0ZTptb2RpZnkAMjAxMS0wNC0wN1QyMTozNjowMisxMDowMApmRdMAAAA2dEVYdFBORzpiS0dEAGNodW5rIHdhcyBmb3VuZCAoc2VlIEJhY2tncm91bmQgY29sb3IsIGFib3ZlKbpeXNkAAAAVdEVYdFBORzpJSERSLmJpdF9kZXB0aAAxNqc4FdcAAAAVdEVYdFBORzpJSERSLmNvbG9yX3R5cGUAMgEnYzIAAAAbdEVYdFBORzpJSERSLmludGVybGFjZV9tZXRob2QAMPs7B4wAAAAedEVYdFBORzpJSERSLndpZHRoLGhlaWdodAAxMDAsIDEwMNtVy6kAAAAkdEVYdFBORzpwSFlzAHhfcmVzPTcyLCB5X3Jlcz03MiwgdW5pdHM9MKQw/n0AAAArdEVYdFBORzp0ZXh0ADIgdEVYdC96VFh0L2lUWHQgY2h1bmtzIHdlcmUgZm91bmRcYYD5AAAAAElFTkSuQmCC";
};
for(var i = 0; i < 10; i++)
{
draw(make_canvas(i));
}
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<body>
<div id="a">
</div>
</body>
I want to be able to click on a button on my page and load an image into a canvas at some X,Y coordinates?
The following code is what I have below. I would like the image to be in either image/photo.jpg or in the same directory but preferably in a subdirectory of the main page.
**Question: How to make a JPG show up in a canvas with the click of a button on the web page?
Code:
<!DOCTYPE html>
<html>
<script>
function draw(){
var ctx = document.getElementById("myCanvas").getContext("2d");
var img = new Image():
// img.src = "2c.jpg";
img.src = "/images/2c.jpg";
ctx.drawImage(img,0,0);
}
</script>
<body background="Black">
<div align="center">
<button type="button" onclick="draw()">Show Image on Canvas</button>
<canvas id="myCanvas" width="900" height="400" style="border:2px solid #d3d3d3;">
Your browser does not support the HTML5 canvas tag.
</canvas>
</div>
<script>
var c=document.getElementById("myCanvas");
var ctx=c.getContext("2d");
ctx.font="20px Arial";
ctx.fillText("Royal Flush $",500,50);
ctx.fillText("Striaght Flush $",500,80);
ctx.fillText("Flush $",500,110);
ctx.fillText("Four of a Kind $",500,140);
ctx.fillText("Full House $",500,170);
ctx.fillText("Three of a Kind $",500,200);
ctx.fillText("Two Pair $",500,230);
ctx.fillText("Pair of ACES $",500,260);
ctx.rect(495,10,270,350);
ctx.stroke();
</script>
</body>
</html>
March 6th, 2014 Code:
How is the following code not working. Do you have to have an ID tag on Canvas. The page will display but for some reason the image will not when the button is clicked. The image is in the same directory that my index.html file is in.
<!DOCTYPE html>
<html>
<head>
<title></title>
</head>
<style type="text/css">
canvas{
border: 5px solid black;
}
</style>
</html>
<button id="galaxy">Add image #1</button>
<button id="circles">Add image #2</button><span></span>
<canvas width="500" height="500"></canvas>
<script>
var Images = {};
function loadImages(list){
var total = 0;
document.querySelector("span").innerText = "...Loading...";
for(var i = 0; i < list.length; i++){
var img = new Image();
Images[list[i].name] = img;
img.onload = function(){
total++;
if(total == list.length){
document.querySelector("span").innerText = "...Loaded.";
}
};
img.src = list[i].url;
}
}
function drawImage(img){
var ctx = document.querySelector("canvas").getContext("2d");
ctx.drawImage(Images[img], 0, 0, 50, 50);
}
loadImages([{
name: "2c.jpg",
url: "mp.jpg"
},{
name: "mp.jpg",
url: "mp.jpg"
}]);
document.querySelector("#galaxy").addEventListener("click", function(){
drawImage("galaxy");
});
document.querySelector("#circles").addEventListener("click", function(){
drawImage("weirdCircles");
});
</script>
</html>
Wait till the image is loaded before drawing:
var img = new Image();
img.onload = function(){ /*or*/ img.addEventListener("load", function(){
ctx.drawImage(img,0,0); ctx.drawImage(img,0,0);
}; };
img.src = "/images/2c.jpg";
Demo: http://jsfiddle.net/DerekL/YcLgw/
If you have more than one image in your game,
It is better to preload all images before it starts.
Preload images: http://jsfiddle.net/DerekL/uCQAH/ (Without jQuery: http://jsfiddle.net/DerekL/Lr9Gb/)
If you are more familiar with OOP: http://jsfiddle.net/DerekL/2F2gu/
function ImageCollection(list, callback){
var total = 0, images = {}; //private :)
for(var i = 0; i < list.length; i++){
var img = new Image();
images[list[i].name] = img;
img.onload = function(){
total++;
if(total == list.length){
callback && callback();
}
};
img.src = list[i].url;
}
this.get = function(name){
return images[name] || (function(){throw "Not exist"})();
};
}
//Create an ImageCollection to load and store my images
var images = new ImageCollection([{
name: "MyImage", url: "//example.com/example.jpg"
}]);
//To pick and draw an image from the collection:
var ctx = document.querySelector("canvas").getContext("2d");
ctx.drawImage(images.get("MyImage"), 0, 0);
Hi I found this code on Stackoverflow for a canvas photo slide show, but I'm just wondering how to make the transitions between images slower?
var loaded = 0, numOfImages = 4;
//first part of chain, invoke async load
var image0 = document.createElement('img'); //this will work in new Chrome
var image1 = document.createElement('img'); //instead of new Image
var image2 = document.createElement('img');
var image3 = document.createElement('img');
//common event handler when images has loaded with counter
//to know that all images has loaded
image0.onload = image1.onload =
image2.onload = image3.onload = function(e) {
loaded+;
if (loaded === numOfImages)
draw(); // <-- second part of chain, invoke loop
}
//show if any error occurs
image0.onerror = image1.onerror =
image2.onerror = image3.onerror = function(e) {
console.log(e);
}
//invoke async loading... you can put these four into your
//window.onload if you want to
image0.src = "img/pic1.jpg";
image1.src = "img/pic2.jpg";
image2.src = "img/pic3.jpg";
image3.src = "img/pic4.jpg";
// this is the main function
function draw() {
var images = new Array(image0, image1, image2, image3),
counter = 0,
maxNum = images.length - 1,
myCanvas = document.getElementById('myCanvas'),
ctx = myCanvas.getContext('2d'),
me = this; //this we need for setTimeout()
//third part of chain, have a function to invoke by setTimeout
this._draw = function() {
//if the next image will cover the canvas
//there is no real need to clear the canvas first.
//I'll leave it here as you ask for this specifically
ctx.clearRect(0, 0, myCanvas.width, myCanvas.height)
ctx.drawImage(images[counter++], 0, 0);
if (counter > maxNum) counter = 0;
setTimeout(me._draw, 1000); //here we use me instead of this
}
this._draw(); //START the loop
}
but I'm just wondering how to make the transitions between images slower?
You have a typo in your onload methods:
loaded++; // instead of loaded+;
The setTimeout controls the delay until me._draw is called again.
For example 3 seconds of delay would be 3000 milliseconds, like this:
setTimeout(me._draw, 3000);
If you instead want an actual transition, you could use something like this:
changing images on a canvas with transitions
Here is code and a Fiddle: http://jsfiddle.net/m1erickson/m8E6J/
<!doctype html>
<html>
<head>
<link rel="stylesheet" type="text/css" media="all" href="css/reset.css" />
<script src="http://code.jquery.com/jquery.min.js"></script>
<style>
body{ background-color: ivory; }
canvas{border:1px solid red;}
</style>
<script>
$(function(){
var loaded = 0, numOfImages = 4;
//first part of chain, invoke async load
var image0 = document.createElement('img'); //this will work in new Chrome
var image1 = document.createElement('img'); //instead of new Image
var image2 = document.createElement('img');
var image3 = document.createElement('img');
//common event handler when images has loaded with counter
//to know that all images has loaded
image0.onload = image1.onload =
image2.onload = image3.onload = function(e) {
loaded++;
if (loaded === numOfImages)
draw(); // <-- second part of chain, invoke loop
}
//show if any error occurs
image0.onerror = image1.onerror =
image2.onerror = image3.onerror = function(e) {
console.log(e);
}
//invoke async loading... you can put these four into your
//window.onload if you want to
image0.src = "https://dl.dropboxusercontent.com/u/139992952/stackoverflow/house204-1.jpg";
image1.src = "https://dl.dropboxusercontent.com/u/139992952/stackoverflow/house204-2.jpg";
image2.src = "https://dl.dropboxusercontent.com/u/139992952/stackoverflow/house204-3.jpg";
image3.src = "https://dl.dropboxusercontent.com/u/139992952/stackoverflow/house204-4.jpg";
// this is the main function
function draw() {
var images = new Array(image0, image1, image2, image3),
counter = 0,
maxNum = images.length - 1,
myCanvas = document.getElementById('myCanvas'),
ctx = myCanvas.getContext('2d'),
me = this; //this we need for setTimeout()
//third part of chain, have a function to invoke by setTimeout
this._draw = function() {
//if the next image will cover the canvas
//there is no real need to clear the canvas first.
//I'll leave it here as you ask for this specifically
ctx.clearRect(0, 0, myCanvas.width, myCanvas.height)
ctx.drawImage(images[counter++], 0, 0);
if (counter > maxNum) counter = 0;
setTimeout(me._draw, 3000); //here we use me instead of this
}
this._draw(); //START the loop
}
}); // end $(function(){});
</script>
</head>
<body>
<canvas id="myCanvas" width=600 height=400></canvas>
</body>
</html>
I have written a javascript that is supposed to scroll pictures across the screen using canvas. I am unable to get this to work and would appreciate any help. I was able to get this to work using one picture and no Array but I want to be able to use an Array and load pictures one after another with a small space between them.
Here's a JSFiddle with my code.
var img = new Image[];
img[0] = new Image;
img[0].src = 'Images/Juniors.jpg';
img[1] = new Image;
img[1].src = 'Images/minis.jpg';
img[2] = new Image;
img[2].src = 'Images/senior.jpg';
var CanvasXSize = 1040;
var CanvasYSize = 240;
var speed = 40; //lower is faster
var scale = 1.05;
var y = -4.5; //vertical offset
var dx = 0.75;
var imgW;
var imgH;
var x = 0;
var clearX;
var clearY;
var ctx;
img.onload = function() {
imgW = img.width*scale;
imgH = img.height*scale;
if (imgW > CanvasXSize) { x = CanvasXSize-imgW; } // image larger than canvas
if (imgW > CanvasXSize) { clearX = imgW; } // image larger than canvas
else { clearX = CanvasXSize; }
if (imgH > CanvasYSize) { clearY = imgH; } // image larger than canvas
else { clearY = CanvasYSize; }
ctx = document.getElementById('canvas').getContext('2d'); //Get Canvas Element
}
function draw() {
//Clear Canvas
ctx.clearRect(0,0,clearX,clearY);
//If image is <= Canvas Size
if (imgW <= CanvasXSize) {
//reset, start from beginning
if (x > (CanvasXSize)) { x = 0; }
//draw aditional image
if (x > (CanvasXSize-imgW)) {
ctx.drawImage(img, x-CanvasXSize+1, y, imgW, imgH);
}
}
//If image is > Canvas Size
else {
//reset, start from beginning
if (x > (CanvasXSize)) { x = CanvasXSize-imgW; }
//draw aditional image
if (x > (CanvasXSize-imgW)) { ctx.drawImage(img[0],x-imgW+1,y,imgW,imgH); }
}
for(i = 0; i < img.length; i++) {
ctx.drawImage(img[i],x,y,imgW,imgH);
//amount to move
x += dx;
}
}
To have multiple images loaded when you need them, you shoud use image preloader code:
var imgs=[];
var imagesOK=0;
var imageURLs=[];
imageURLs.push("https://dl.dropboxusercontent.com/u/139992952/stackoverflow/house1.jpg");
imageURLs.push("https://dl.dropboxusercontent.com/u/139992952/stackoverflow/house2.jpg");
imageURLs.push("https://dl.dropboxusercontent.com/u/139992952/stackoverflow/house3.jpg");
loadAllImages();
function loadAllImages(){
for (var i = 0; i < imageURLs.length; i++) {
// put each image in the imgs array
var img = new Image();
imgs.push(img);
// after each image has been loaded, execute this function
img.onload = function(){
// add 1 to imagesOK
imagesOK++;
// if imagesOK equals the # of images in imgs
// we have successfully preloaded all images
// into imgs[]
if (imagesOK>=imageURLs.length ) {
// all loaded--start drawing the images
drawImages();
}
}; // end onload
img.src = imageURLs[i];
} // end for
}
At this point the images are all loaded, so draw the images
You can use context.translate and context.rotate to tilt your images.
What you do is translate (move) to the center of the image you want to rotate. Then do the rotation from that centerpoint. That way the image will rotate around its center. The rotate function takes a radian angle so you can translate degrees to radians like this: 30 degrees = 30 * Math.PI/180 radians
ctx.translate( left+width/2, topp+height/2 )
ctx.rotate( degrees*Math.PI/180 );
Then you draw your image offset by its centerpoint (remember you’re rotating around that centerpoint)
ctx.drawImage(img,0,0,img.width,img.height,-width/2,-height/2,width,height);
It’s a lot to wrap your head around so here’s example code and a Fiddle: http://jsfiddle.net/m1erickson/t49kU/
<!doctype html>
<html>
<head>
<link rel="stylesheet" type="text/css" media="all" href="css/reset.css" /> <!-- reset css -->
<script type="text/javascript" src="http://code.jquery.com/jquery.min.js"></script>
<style>
body{ background-color: ivory; }
canvas{border:1px solid red;}
</style>
<script>
$(function(){
var canvas=document.getElementById("canvas");
var ctx=canvas.getContext("2d");
var imgs=[];
var imagesOK=0;
var imageURLs=[];
imageURLs.push("https://dl.dropboxusercontent.com/u/139992952/stackoverflow/house1.jpg");
imageURLs.push("https://dl.dropboxusercontent.com/u/139992952/stackoverflow/house2.jpg");
imageURLs.push("https://dl.dropboxusercontent.com/u/139992952/stackoverflow/house3.jpg");
loadAllImages();
function loadAllImages(){
for (var i = 0; i < imageURLs.length; i++) {
var img = new Image();
imgs.push(img);
img.onload = function(){
imagesOK++;
if (imagesOK>=imageURLs.length ) {
drawImages();
}
}; // end onload
img.src = imageURLs[i];
} // end for
}
ctx.lineWidth=2;
var left=25;
var topp=30;
var width=100;
var height=100;
var rotations=[ -10, 0, 10 ];
function drawImages(){
for(var i=0;i<imgs.length;i++){
var img=imgs[i];
ctx.save()
ctx.beginPath();
ctx.translate( left+width/2, topp+height/2 )
ctx.rotate(rotations[i]*Math.PI/180);
ctx.drawImage(img,0,0,img.width,img.height,-width/2,-height/2,width,height);
ctx.rect(-width/2,-height/2,width,height);
ctx.stroke();
ctx.restore();
left+=125;
}
}
}); // end $(function(){});
</script>
</head>
<body>
<canvas id="canvas" width=400 height=200></canvas>
</body>
</html>