The problem I have is that when the page is loaded sometimes it displays all the images, sometimes just 2 images and sometimes all. I don´t know why this is happening.
Any ideas?
$('#banners .box img').each(function(index){
var randval = (index+1)*100;
var _this = $(this)
setTimeout(function(){
_this.attr('id' , 'banner' + index);
to_canvas('banner' + index, 300, 223);
}, randval)
});
to_canvas function:
function to_canvas(im,w,h){
var canvas;
var imageBottom;
var im_w = w;
var im_h = h;
var imgData;
var pix;
var pixcount = 0;
var paintrow = 0;
var multiplyColor = [70, 116, 145];
var x_offset = Math.floor(($('#'+im).attr('width') - im_w)/2);
var y_offset = Math.floor(($('#'+im).attr('height') - im_h)/2);
imageBottom = document.getElementById(im);
canvas = document.createElement('canvas');
canvas.width = im_w;
canvas.height = im_h;
imageBottom.parentNode.insertBefore(canvas, imageBottom);
ctx = canvas.getContext('2d');
ctx.drawImage(imageBottom, -x_offset , -y_offset);
imgData = ctx.getImageData(0, 0, canvas.width, canvas.height);
pix = imgData.data;
for (var i = 0 ; i < pix.length; i += 4) {
if(pixcount > im_w - (im_h - paintrow) ){
pix[i ] = multiply(multiplyColor[0], pix[i ]);
pix[i+1] = multiply(multiplyColor[1], pix[i+1]);
pix[i+2] = multiply(multiplyColor[2], pix[i+2]);
}
if(pixcount < im_w-1){
pixcount++;
}else{
paintrow++;
pixcount = 0;
}
}
ctx.putImageData(imgData, 0, 0);
$('#'+im).remove();
}
function multiply(topValue, bottomValue){
return topValue * bottomValue / 255;
}
I'm using the canvas function to add a triangle with multiply effect (like Photoshop).
Make sure the images are loaded :
$('#banners .box img').each(function(index, elem){
var randval = (index+1)*100,
self = this,
img = new Image(); // create image object
img.onload = function() { // wait until it's loaded
setTimeout(function(){
self.id = 'banner' + index;
to_canvas('banner' + index, 300, 223);
}, randval)
}
img.src = elem.src; // set source to same as elem
});
Wrap it all in this code to make sure the images are loaded before you execute your script. When you initially load your page, it caches the images(stores them in temp memory), but not before all your elements are rendered. When you reload, it reads the images from the cache–which is much faster than refetching the images again from the server–and therefore the images load about the same time everything else does. This results in visible images.
Like I said, to get your page to work, make sure everything is loaded, then run your script.
$(window).load(function(){
...your scripts(you can exclude functions definitions from this scope)
}
Related
i am getting frames from gif using Libgif.
and then i am appending those frames in the div with Id = frames.
then i am taking those frames and trying to add each frames one after the other in canvas to make a spritesheet.
in the end i am getting an image in canvas but instead of getting different frames i am getting same image in the spritesheet.
Please help me find the issue.
I had taken canvas width 10000 assuming a gif wont have frames more than 100.
c = document.getElementById("myCanvas");
ctx = c.getContext("2d");
ctx.clearRect(0, 0, ctx.width, ctx.height);
ctx.beginPath();
var imageGiF = "";
var total = 0;
let canvasWidth = 0;
let canvasHeight = 0;
$('div.gifimage img').each(function(idx, img_tag) {
var total = 0;
if (/^.+\.gif$/.test($(img_tag).prop("src"))) {
var rub = new SuperGif({
gif: img_tag,
progressbar_height: 0
});
rub.load(function() {
for (let i = 0; i < rub.get_length(); i++) {
total += 1;
rub.move_to(i);
// var canvas = cloneCanvas(rub.get_canvas());
var canvas = rub.get_canvas().toDataURL("image/png");
img = $('<img id = "gifframe' + i + '"src= "' + canvas + '" class= frameimages>');
$("#frames").append(img);
}
var frameimages = document.getElementById("frames").querySelectorAll(".frameimages");
var totalimages = frameimages.length;
x = 0;
y = 0;
for (let i = 0; i < frameimages.length; i++) {
img = document.getElementById("gifframe" + i + "");
img.onload = function() {
ctx.drawImage(img, i * 100, 0, 100, 100);
total++;
console.log(total);
}
}
totalwidth = (total) * 100;
c.width = totalwidth;
c.height = 100;
setTimeout(() => {
imageGiF = c.toDataURL("image/png");
console.log(imageGiF);
// addBgimg(imageGiF)
}, 10);
});
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
<script src="https://cdn.rawgit.com/buzzfeed/libgif-js/master/libgif.js"></script>
<div class="gifimage" id="placehere">
<img src="https://media1.giphy.com/media/bzUwzbxcvJ3XQlcnoi/giphy.gif" alt="">
</div>
<div id="frames" class="classGIF"></div>
<canvas id='myCanvas' width="10000" height="300"></canvas>
You were looping through the images, using img in your event handler.
However, this variable img in the outer scope was overridden by every loop, until it was finished looping through everything, then img was stuck on the last frame added.
Then when the event handler triggered, it added the last frame in every instance, because that was the value of img at that point. The loop was done before the images could load.
By adding it to it's own scope by wrapping it in a function, the variable is preserved.
I also modified your code to store the DOM img elements in an array, so you don't need expensive DOM lookups which makes your code a tad bit faster.
I added comments in the code to explain my changes.
c = document.getElementById("myCanvas");
ctx = c.getContext("2d");
ctx.clearRect(0, 0, ctx.width, ctx.height);
ctx.beginPath();
var imageGiF = "";
var total = 0;
let canvasWidth = 0;
let canvasHeight = 0;
$('div.gifimage img').each(function(idx, img_tag) {
var total = 0;
if (/^.+\.gif$/.test($(img_tag).prop("src"))) {
var rub = new SuperGif({
gif: img_tag,
progressbar_height: 0
});
rub.load(function() {
// An array for the image references
let images = [];
// Keep the reference to save on expensive DOM lookups every iteration.
let frames = $("#frames");
for (let i = 0; i < rub.get_length(); i++) {
total += 1;
rub.move_to(i);
// var canvas = cloneCanvas(rub.get_canvas());
var canvas = rub.get_canvas().toDataURL("image/png");
img = $('<img id = "gifframe' + i + '"src= "' + canvas + '" class="frameimages">');
// Use the reference to append the image.
frames.append(img);
// Add image to images array with the current index as the array index.
// Use the jQuery get method to get the actual DOM element.
images[i] = img.get(0);
}
var frameimages = document.getElementById("frames").querySelectorAll(".frameimages");
var totalimages = frameimages.length;
x = 0;
y = 0;
// Loop through all the images in the image array
// Using a scope so the reference to img won't be overridden.
images.forEach((img, index) => {
img.onload = () => {
ctx.drawImage(img, index * 100, 0, 100, 100);
total++;
console.log(total);
}
})
totalwidth = (total) * 100;
c.width = totalwidth;
c.height = 100;
setTimeout(() => {
imageGiF = c.toDataURL("image/png");
console.log(imageGiF);
// addBgimg(imageGiF)
}, 10);
});
}
});
#frames { display:none;}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
<script src="https://cdn.rawgit.com/buzzfeed/libgif-js/master/libgif.js"></script>
<div class="gifimage" id="placehere">
<img src="https://media1.giphy.com/media/bzUwzbxcvJ3XQlcnoi/giphy.gif" alt="">
</div>
<div id="frames" class="classGIF"></div>
<canvas id='myCanvas' width="10000" height="300"></canvas>
I have a canvas animation that has been created with createjs. The entire animation script including init() function is loaded via jquery: $.getScript() on page load.
The init() and handlecomplete() function included below is then run which attaches the animation to a html canvas element on the page.
var canvas, stage, exportRoot, audio;
var tweens = [];
function init() {
canvas = document.getElementById("canvas");
images = images||{};
if (stage) {
stage.enableDOMEvents(false);
stage.removeAllChildren();
createjs.Ticker.removeAllEventListeners()
stage.enableDOMEvents(true);
}
if (audio ) {
audio.stop();
}
removeTweens();
exportRoot = null;
audio = null;
stage = null;
var loader = new createjs.LoadQueue(false);
loader.installPlugin(createjs.Sound);
loader.addEventListener("fileload", handleFileLoad);
loader.addEventListener("complete", handleComplete);
loader.loadManifest(lib.properties.manifest);
}
function handleComplete() {
exportRoot = new lib.animation2();
stage = new createjs.Stage(canvas);
stage.addChild(exportRoot);
stage.update();
stage.canvas.width = 1280;
stage.canvas.height = 720;
resizeToFit();
stage.update();
createjs.Ticker.setFPS(lib.properties.fps);
createjs.Ticker.addEventListener("tick", stage);
createjs.Ticker.addEventListener("tick", updateTimer);
if (lib.properties.audiovolume) {
audio = createjs.Sound.play("audio", createjs.Sound.INTERRUPT_EARLY, 0, 0, -1, lib.properties.audiovolume);
}
exportRoot.gotoAndPlay(startFrame );
}
My issue is when the user makes a change, we load the script a second time using the same jquery method which returns the updated script. The init() function then executes properly and the new animation plays correctly, but our animated text (using the animateText below) does not appear on the canvas. This function is also loaded dynamically with other functions.
Checking the tween arrays, they are being created and removed as required, but they are not visible.
They are either layered behind the new animation, or not being attached to the new canvas or something else?
Simply refreshing the page will then load the new script and text properly. So clearly something in the dynamic loading of the script?
var animateText = function(localString, startX, startY, letterClip, endObject, font, color) {
var waitAmount = 0;
var offSetAmount = 20;
for(var i = 0; i < localString.length; i++){
var fl_MyInstance = new letterClip();
fl_MyInstance.localName.text = localString[i];
if(font != null){
fl_MyInstance.localName.font = font;
}
if(color != null){
fl_MyInstance.localName.color = color;
}
var localX = startX;
var localY = startY;
fl_MyInstance.x = startX + offSetAmount;
var beginX = startX + offSetAmount
offSetAmount = offSetAmount - 4
fl_MyInstance.y = startY;
fl_MyInstance.alpha = 0;
fl_MyInstance.scaleX = 0.1;
fl_MyInstance.scaleY = 0.1;
var bounds = fl_MyInstance.getBounds();
startX += bounds.width + 0;
var target = fl_MyInstance;
var tween = createjs.Tween.get(target, {
loop: false
}).wait(waitAmount)
.to({
x: localX,
y: localY,
alpha: 1,
scaleX: 1,
scaleY: 1
}, 400, createjs.Ease.circOut);
tween.waitAmount = waitAmount;
if(endObject == null){
tween.endObject = {
x: localX,
y: localY,
alpha: 0,
scaleX: 0.1,
scaleY: 0.1
}
} else {
tween.endObject = {
x: localX - endObject.x,
y: localY - endObject.y,
alpha: endObject.alpha,
scaleX: endObject.scaleX,
scaleY: endObject.scaleY
}
}
tween.targetClip = fl_MyInstance;
tween.arrayIndex = tweens.length;
tweens.push(tween);
waitAmount += 20;
stage.addChild(fl_MyInstance);
}
}
var removeTweens = function(){
for(var i = 0; i<tweens.length; i++){
if(tweens[i] != null){
var tween = tweens[i];
stage.removeChild(tween.targetClip);
tweens[tween.arrayIndex] = null;
}
}
}
var closeTweens = function(){
for(var i = 0; i<tweens.length; i++){
if(tweens[i] != null){
var tween = tweens[i];
createjs.Tween.get(tween.targetClip, {
loop: false
}).wait(tween.waitAmount).to(tween.endObject, 400, createjs.Ease.circOut).call(function(){
stage.removeChild(tween.targetClip);
tweens[tween.arrayIndex] = null;
});
}
}
}
var finalTweens = function(){
for(var i = 0; i<tweens.length; i++){
if(tweens[i] != null){
var tween = tweens[i];
createjs.Tween.get(tween.targetClip, {
loop: false
}).to(tween.endObject, 400, createjs.Ease.circOut);
}
}
}
Since the rest of the animation works perfectly using this method of dynamic loading, I don't think it is something in the loading. But there must be something missing in animateText and reloading functions that causes the issue.
Currently having some issues with drawImage();. Namely it wont actually draw. I tried it out with fillRect(); and it worked aswell as putting the drawImage(); inside the the onload function aswell (which worked).
var canvas = document.createElement("canvas");
var ctx = canvas.getContext("2d");
canvas.width = 640;
canvas.height = 400;
document.body.appendChild(canvas);
var tileArray = [
[0,0,0,0,0,0,0,0,0,0,0,0,0],
[0,0,0,1,1,1,1,0,0,1,0,0,0],
[0,0,0,1,1,1,1,0,1,1,1,0,0],
[0,0,0,1,1,1,0,0,0,0,1,1,0],
[0,0,0,1,1,1,0,0,0,0,0,0,0],
[0,0,0,1,1,1,0,0,0,0,0,0,0],
[0,0,0,0,1,1,1,0,0,0,0,0,0],
[0,0,0,0,1,1,1,0,0,0,0,0,0],
[0,0,0,0,0,1,1,1,0,0,0,0,0],
[0,0,0,0,0,0,1,1,0,0,0,0,0]
];
var grassReady = false;
var grass = new Image();
grass.onload = function() {
grassReady = true;
};
grass.src = "images/grass.png";
var sandReady = false;
var sand = new Image();
sand.onload = function() {
sandReady = true;
};
sand.src = "images/sand.png";
var posX = 0;
var posY = 0;
if(grassReady) {
ctx.drawImage(grass, posX, posY);
}
Any pointers as to why this is would be greatly appreciated and I appologize in advance if messed up the code section in anyway. I went through other similar posts and coulden't find a solution that seemed to work.
As #Suman Bogati correctly says, you must wait for your images to load before using them in drawImage.
A Demo: http://jsfiddle.net/m1erickson/jGPGj/
Here's an image loader that preloads all images and then calls the start() function where you can use drawImage because all the images are fully loaded.
var imageURLs=[]; // put the paths to your images here
var imagesOK=0;
var imgs=[];
imageURLs.push("images/grass.png");
imageURLs.push("images/sand.png");
loadAllImages(start);
function loadAllImages(callback){
for (var i=0; i<imageURLs.length; i++) {
var img = new Image();
imgs.push(img);
img.onload = function(){
imagesOK++;
if (imagesOK>=imageURLs.length ) {
callback();
}
};
img.onerror=function(){alert("image load failed");}
img.crossOrigin="anonymous";
img.src = imageURLs[i];
}
}
function start(){
// the imgs[] array holds fully loaded images
// the imgs[] are in the same order as imageURLs[]
// grass.png is in imgs[0]
// sand.png is in imgs[1]
}
This statement ctx.drawImage(); should be inside the grass.onload = function() {} function, something like
grass.onload = function() {
ctx.drawImage(grass, posX, posY);
}
If you define drawImage() outside the grass.onload() function, then that statment would executed first, so at that point grassReady is false, So the condition is not satisfied.
Bascially it's related to asynchronous concept.
Your code is running into order
1) First
var grassReady = false;
if(grassReady) {
//grassReady is false, this condition is not satisfied
ctx.drawImage(grass, posX, posY);
}
2) Second
grass.onload = function() {
grassReady = true;
};
I am new with jquery , i have a small project about display image with canvas. All will good , but i have a trouble when try display all image , i try to use .each(function) or loop but not work
This is my trouble , any one can help ?. Thanks
http://jsfiddle.net/NcKfr/6/
<textarea id="textid">blah blah blah</textarea>
<canvas id="ca1" width="640" height="480"></canvas>
<script>
$(document.body).find('*').each(function() {
var tmp = $("textarea").children().remove();
var text = $("textarea").text();
text = text.replace(/<li>/g, "").replace(/<\/li>/g, "").replace(/<br \/>/g, "").replace(/\/>/g, "").replace(/<img/g, "").replace(/ /g, "");
$("textarea").text(text);
$("textarea").append(tmp);
});
</script>
Script code :
$(function(e) {
var data = $("#textid").val();
rows = data.split('src="');
partNum = [];
var i;
var len = rows.length;
var can = document.getElementsByTagName('canvas')[0];
var ctx = can.getContext('2d');
$(document).ready(function() {
for (i = 1; i < len; i++) {
partNum[i] = rows[i].substr(0,rows[i].indexOf('"'));
$.getImageData({
url: partNum[i],
success: function(image) {
// Set the canvas width and heigh to the same as the image
$(can).attr('width', image.width);
$(can).attr('height', image.height);
$(can).css({
'background-color': 'none',
'border-color': '#fff'
});
// Draw the image on to the canvas
ctx.drawImage(image, 0, 0, image.width, image.height);
},
error: function(xhr, text_status) {
// Handle your error here
}
});
}
});
});
success: function(image) {
script = document.createElement('canvas');
var can = document.body.appendChild(script);
If i change code in two line , i can show all image but i can control it load form 1 to 13. Any body can help me fix it ... thanks
Here is a code which will draw images on one canvas one under another.
var url = "http://farm4.static.flickr.com/",
urls = [
"3002/2758349058_ab6dc9cfdc_z.jpg",
"2445/5852210343_d21767f18d.jpg"],
can = $('#canvas').get(0),
ctx = can.getContext('2d'),
canH = 0,
canW = 0,
h = 0,
images = [],
size = urls.length;
// loop via all images
$.each(urls, function (index, img) {
$.getImageData({
url: url + img,
success: function (image) {
images.push(image);
canH += image.height;
canW = Math.max(canW, image.width);
if (images.length === size) {
can.width = canW;
can.height = canH;
$.each(images, function (i, img) {
ctx.drawImage(img, 0, h);
h += img.height;
});
}
}
});
});
You can also check this: http://jsfiddle.net/HcxG3/6/ (looks like the service behind getImageData is currently down).
I have been trying to make a script that compares two images in HTML5 and Javascript. But for some odd reason, it always returns that the images are completely the same.
And when looking at what the problem could be, I found out that every data value of every pixel returned, for some odd reason, "0".
So, any idea of what I have done wrong? :)
For some reason I feel like it's something very simple, but I just learned about the canvas element, so yeah.
This is my code:
function compareImg() {
var c1 = document.getElementById("c");
var ctx1 = c1.getContext("2d");
var c2 = document.getElementById("c2");
var ctx2 = c2.getContext("2d");
var match = 0;
var img1 = new Image();
img1.src = "cat.jpg";
img1.onload = function() {
ctx1.drawImage(img1, 0, 0);
}
var img2 = new Image();
img2.src = "bird.jpg";
img2.onload = function() {
ctx2.drawImage(img2, 0, 0);
}
for(var x = 0; x<c1.width; x++) { // For each x value
for(var y = 0; y<c1.height; y++) { // For each y value
var data1 = ctx1.getImageData(x, y, 1, 1);
var data2 = ctx2.getImageData(x, y, 1, 1);
if (data1.data[0] == data2.data[0] && data1.data[1] == data2.data[1] && data1.data[2] == data2.data[2]) {
match++;
}
}
}
var pixels = c1.width*c1.height;
match = match/pixels*100;
document.getElementById("match").innerHTML = match + "%";
}
You are not waiting until your images have loaded and drawn before performing your comparison. Try this:
var img = new Image;
img.onload = function(){
ctx1.drawImage(img,0,0);
var img = new Image;
img.onload = function(){
ctx2.drawImage(img,0,0);
// diff them here
};
img.src = 'cat.jpg';
};
img.src = 'cat.jpg';
As shown above, you should always set your src after your onload.
I suspect that the problem is that your image data is probably not ready at the point you try to use it for the canvas. If you defer that code to the onload handlers, that will (probably) help:
var img1 = new Image(), count = 2;
img1.src = "cat.jpg";
img1.onload = function() {
ctx1.drawImage(img1, 0, 0);
checkReadiness();
}
var img2 = new Image();
img2.src = "bird.jpg";
img2.onload = function() {
ctx2.drawImage(img2, 0, 0);
checkReadiness();
}
function checkReadiness() {
if (--count !== 0) return;
for(var x = 0; x<c1.width; x++) { // For each x value
for(var y = 0; y<c1.height; y++) { // For each y value
var data1 = ctx1.getImageData(x, y, 1, 1);
var data2 = ctx2.getImageData(x, y, 1, 1);
if (data1.data[0] == data2.data[0] && data1.data[1] == data2.data[1] && data1.data[2] == data2.data[2]) {
match++;
}
}
}
var pixels = c1.width*c1.height;
match = match/pixels*100;
document.getElementById("match").innerHTML = match + "%";
}
All I did was add a function wrapper around your code. That function checks the image count variable I added, and only when it's zero (i.e., only after both images have loaded) will it do the work.
(This may be superstition, but I always assign the "onload" handler before I set the "src" attribute. I have this idea that, perhaps only in the past, browsers might fail to run the handler if the image is already in the cache.)
Now another thing: you probably should just get the image data once, and then iterate over the returned data. Calling "getImageData()" for every single pixel is going to be a lot of work for the browser to do.