Canvas patterned pie chart with array image - javascript

I am trying to make a pie chart made by patterns using some images. But I can't see any images which I am trying to show. What is the problem with the following codes?
<html>
<body>
<canvas width="250" height="250" id="canvas"></canvas>
<script>
var imgArray = new Array();
imgArray[0] = new Image();
imgArray[0].src = 'p2.jpg';
imgArray[1] = new Image();
imgArray[1].src = 'p3.jpg';
imgArray[2] = new Image();
imgArray[2].src = 'p4.jpg';
imgArray[3] = new Image();
imgArray[3].src = 'p5.jpg';
imgArray[4] = new Image();
imgArray[4].src = 'p6.jpg';
//initialize data set
var data = [ 100, 68, 20, 30, 100 ];
var canvas = document.getElementById('canvas');
var c = canvas.getContext('2d');
//draw background
c.fillStyle = "white";
c.fillRect(0,0,500,500);
//a list of colors
//calculate total of all data
var total = 0;
for(var i=0; i<data.length; i++) {
total += data[i];
}
var prevAngle = 0;
for(var i=0; i<data.length; i++) {
//fraction that this pieslice represents
var fraction = data[i]/total;
In this step, I dynamically try to put the images into the pie chart, but I think the 'src' usage is wrong.
//calc starting angle
var angle = prevAngle + fraction*Math.PI*2;
var pat=c.createPattern(imgArray[i].src,"repeat");
//draw the pie slice
//create a path
c.beginPath();
c.moveTo(250,250);
c.arc(250,250, 100, prevAngle, angle, false);
c.lineTo(250,250);
c.closePath();
//fill it
c.fillStyle = pat;
c.fill();
//stroke it
c.strokeStyle = "black";
c.stroke();
//update for next time through the loop
prevAngle = angle; </script> </body> </html>

You are correct in your suspicion.
createPattern takes an image object--not a URL.
var pat;
var img=new Image();
img.onload=function(){
pat=c.createPattern(img,"repeat");
// now you can create a path and fill it with `pat`
}
img.src="http://whatever.com/whatever.png";
[ Added image loader code in response to additional question ]
// image loader
var imageURLs=[]; // put the paths to your images here
var imagesOK=0;
var imgArray=[];
imageURLs.push("p2.jpg");
imageURLs.push("p3.jpg");
imageURLs.push("p4.jpg");
imageURLs.push("p5.jpg");
imageURLs.push("p6.jpg");
loadAllImages(start);
function loadAllImages(callback){
for (var i=0; i<imageURLs.length; i++) {
var img = new Image();
imgArray.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 imgArray[] array now holds fully loaded images
// the imgArray[] are in the same order as imageURLs[]
// imgArray[0] is p2.jpg
// imgArray[1] is p3.jpg
// imgArray[2] is p4.jpg
// imgArray[3] is p5.jpg
// imgArray[4] is p6.jpg
// create your patterns now
}

Related

Refresh the image without reloading the page

Each new image should be with different src. Untill reloading all images have single src. It is can be add location.reload(); until adding new image, then scr will change. But reloading very seen. Does it exist way to reload only scr?
var cvs;
var ctx;
cvs = document.getElementById("canvas");
ctx = cvs.getContext("2d");
var width_path_near = 80,
width_path_far = 30;
var tree1 = new Image();
var tree2 = new Image();
var tree3 = new Image();
var tree4 = new Image();
tree1.src = "https://png.pngtree.com/element_origin_min_pic/00/02/61/6156839a2a633b7.jpg";
tree2.src = "http://s02.yapfiles.ru/files/457732/derevo_1.png";
tree3.src = "http://www.grafamania.net/uploads/posts/2014-06/1401644723_1-9.jpg";
tree4.src = "http://img11.txapela.ru/e/c/c/4/f/52e052f118c7b8ff9317385f581.jpg";
var masTree=[tree1, tree2, tree3, tree4];
var randTree=Math.floor(Math.random()*masTree.length);
var tree_size = 100;
var grow = 0.2;
var gap = 100;
var forest = [];
forest[0] = {
x : cvs.width/2-width_path_near-tree_size/2,
y : cvs.height/2-tree_size+10,
size : tree_size
}
function draw() {
ctx.fillStyle = "rgb(84,209,216)";
ctx.fillRect(0, 0, 1000, 600);
for (var i=0; i<forest.length; i++){
ctx.drawImage(masTree[randTree], forest[i].x, forest[i].y, forest[i].size, forest[i].size);
if(forest[i].y == 3*cvs.height/4){
forest.push({
y : cvs.height/2-tree_size+10,
x : cvs.width/2-width_path_near-tree_size/2,
size : tree_size
});
}
forest[i].y += 0.5;
forest[i].x -= 0.4;
forest[i].size += 0.4;
}
requestAnimationFrame(draw);
}
masTree[randTree].onload = draw;
http://jsfiddle.net/Nata_Hamster/ugyb1fd0/

how to draw multiple images in canvas

I need to draw images in their own canvas. What am I doing wrong?
If I delete the "for loop" the code works just fine (e.g: set var i=0, then img[0] is drawn in canv[0]).
window.onload = function() {
var canv = [];
var ctx = [];
var img = [];
var info = [{"url":"1.jpg"},{"url":"2.jpg"},{"url":"3.jpg"}];
for(i=0; i< 3; i++){
canv[i] = document.createElement('canvas');
canv[i].width = 460;
canv[i].height = 620;
canv[i].style.border = "1px solid";
document.body.appendChild(canv[i]);
img[i] = new Image();
img[i].src = info[i].url;
ctx[i] = canv[i].getContext("2d");
img[i].onload = function(){
ctx[i].drawImage(img[i], 10, 70, 440,440);
}
}
}
Found the solution, just in case somebody has the same problem:
(function (_i) {
img[_i] = new Image();
img[_i].src = info[_i].url;
img[_i].onload = function () {
ctx[_i].drawImage(img[_i], 10, 70, 440,440);
};
})(i);

html5 Canvas drawimage background + 9 images

I have a little problem, sometimes work or not work drawimage, i tried to begin with draw background and if drawed then next draw 9 images(sometimes images is this same or not same).
var c = document.getElementById('myCanvas');
var ctx = c.getContext("2d");
$('button').on('click',function(){
var img = new Image();
var img1 = new Image();
var img2 = new Image();
var img3 = new Image();
var img4 = new Image();
var img5 = new Image();
var img6 = new Image();
var img7 = new Image();
var img8 = new Image();
var img9 = new Image();
img.src = $(location).attr('href')+'/img/frames/'+$('#frames option:selected').val();
img1.src = $(location).attr('href')+'/img/mercmain/'+$('#merc1 option:selected').val();
img2.src = $(location).attr('href')+'/img/mercmain/'+$('#merc2 option:selected').val();
img3.src = $(location).attr('href')+'/img/mercmain/'+$('#merc3 option:selected').val();
img4.src = $(location).attr('href')+'/img/mercmain/'+$('#merc4 option:selected').val();
img5.src = $(location).attr('href')+'/img/mercmain/'+$('#merc5 option:selected').val();
img6.src = $(location).attr('href')+'/img/mercmain/'+$('#merc6 option:selected').val();
img7.src = $(location).attr('href')+'/img/mercmain/'+$('#merc7 option:selected').val();
img8.src = $(location).attr('href')+'/img/mercmain/'+$('#merc8 option:selected').val();
img9.src = $(location).attr('href')+'/img/mercmain/'+$('#merc9 option:selected').val();
img.onload = function(){
ctx.clearRect(0, 0, c.width, c.height);
ctx.drawImage(img, 0, 0,307,382);
img1.onload = function(){
ctx.drawImage(img1,$xyframe[0][0],$xyframe[0][1],$xyframe[0][2],$xyframe[0][3]);
};
img2.onload = function(){
ctx.drawImage(img2,$xyframe[1][0],$xyframe[1][1],$xyframe[1][2],$xyframe[1][3]);
};
img3.onload = function(){
ctx.drawImage(img3,$xyframe[2][0],$xyframe[2][1],$xyframe[2][2],$xyframe[2][3]);
};
img4.onload = function(){
ctx.drawImage(img4,$xyframe[3][0],$xyframe[3][1],$xyframe[3][2],$xyframe[3][3]);
};
img5.onload = function(){
ctx.drawImage(img5,$xyframe[4][0],$xyframe[4][1],$xyframe[4][2],$xyframe[4][3]);
};
img6.onload = function(){
ctx.drawImage(img6,$xyframe[5][0],$xyframe[5][1],$xyframe[5][2],$xyframe[5][3]);
};
img7.onload = function(){
ctx.drawImage(img7,$xyframe[6][0],$xyframe[6][1],$xyframe[6][2],$xyframe[6][3]);
};
img8.onload = function(){
ctx.drawImage(img8,$xyframe[7][0],$xyframe[7][1],$xyframe[7][2],$xyframe[7][3]);
};
img9.onload = function(){
ctx.drawImage(img9,$xyframe[8][0],$xyframe[8][1],$xyframe[8][2],$xyframe[8][3]);
};
};
});
and link to test script https://tajkjs-olszam.c9users.io/genform/
and if i remove from img1-9.onload, leave ctx.drawimage(img1-9) and make settimeout from 3 to 5 sec then it's ok but i want without settimeout.
setTimeout(function(){
//img.onload = function(){
ctx.drawImage(img, 0, 0,307,382);
// };
ctx.drawImage(img1,$xyframe[0][0],$xyframe[0][1],$xyframe[0][2],$xyframe[0][3]);
ctx.drawImage(img2,$xyframe[1][0],$xyframe[1][1],$xyframe[1][2],$xyframe[1][3]);
ctx.drawImage(img3,$xyframe[2][0],$xyframe[2][1],$xyframe[2][2],$xyframe[2][3]);
ctx.drawImage(img4,$xyframe[3][0],$xyframe[3][1],$xyframe[3][2],$xyframe[3][3]);
ctx.drawImage(img5,$xyframe[4][0],$xyframe[4][1],$xyframe[4][2],$xyframe[4][3]);
ctx.drawImage(img6,$xyframe[5][0],$xyframe[5][1],$xyframe[5][2],$xyframe[5][3]);
ctx.drawImage(img7,$xyframe[6][0],$xyframe[6][1],$xyframe[6][2],$xyframe[6][3]);
ctx.drawImage(img8,$xyframe[7][0],$xyframe[7][1],$xyframe[7][2],$xyframe[7][3]);
ctx.drawImage(img9,$xyframe[8][0],$xyframe[8][1],$xyframe[8][2],$xyframe[8][3]);
},100);
this code is work but unfortunately I have use settimeout
Try not to draw on each image load. Use counter for loaded images and run draw function on last load. Also Pablo said right thing - set onload listener before set source. This code should run inside your click listener function
var img;
var counter = 0;
var imagesLength = 9;
var images = [];
var backgroundImage = new Image();
var imgFolder = location.href+'/img/mercmain/';
function drawImages(){
ctx.clearRect(0, 0, c.width, c.height);
ctx.drawImage(backgroundImage, 0, 0,307,382); //draw background
for ( var i=0; i<imagesLength ; i++ ){ //draw images
ctx.drawImage(images[i],$xyframe[i][0],$xyframe[i][1],$xyframe[i][2],$xyframe[i][3]);
}
}
function onLoad(){
counter++;
if( counter === imagesLength + 1 ){ // +1 - we must count also background image
drawImages(); // draw all the images at once
}
}
for ( var i=0; i<imagesLength ; i++ ){
img = new Image();
images.push( img ); // push in array before src,
// onload should not fire while image is not in array
img.onload = onLoad; // set onload before src,
// image should not load before onload listener is set
img.src = imgFolder + $('#merc'+ (i+1) +' option:selected').val();
}
// do not forget to set the same for background image
backgroundImage.onload = onLoad;
backgroundImage.src = location.href + '/img/frames/' + $('#frames option:selected').val();
You have a race condition: You are loading all the images at the same time, but if the background image is not the first one to be loaded, you are adding the onload listeners AFTER the images have been loaded, so the event has already happened and the drawing logic is never executed.
Solution? the imgN.onload=function() {...} assignments should be outside the img.onload function:
$('button').on('click',function(){
var img = new Image();
var imgArr=[];
for (var i=0;i<9;i++) {
imgArr[i]=new Image();
}
img.src = $(location).attr('href')+'/img/frames/'+$('#frames option:selected').val();
for (var i=0;i<9;i++) {
imgArr[i].src=$(location).attr('href')+'/img/mercmain/'+$('#merc'+i+' option:selected').val();
}
img.onload = function(){
ctx.clearRect(0, 0, c.width, c.height);
ctx.drawImage(img, 0, 0,307,382);
}
//Here, instead in the previous function
for (var i=0;i<9;i++) {
imgArr[i].onload = function(){
ctx.drawImage(img1,$xyframe[i][0],$xyframe[i][1],$xyframe[i][2],$xyframe[i][3]);
};
}
});

Converting images to base64 within a loop before adding to jspdf - javascript

I have researched issues with the base64 conversion and jspdf function quite a bit. ( PS this is my first question on stackoverflow, please bare with any rookie mistakes ).
All seems to work fine with the below code except that the pdf is generated and saved before the loop where the images are converted to base64 and placed to the document is finished. I added a couple alerts to check timing. Would the solution be to check when the loop is finished, the images placed before continuing with the pdf function? if so, how? please help.
$(document).ready(function(){
$("a#getdoc").click(function(){
var doc = new jsPDF('landscape, in, legal');
var myimages = 'img1.jpg|img2.jpg|img3.png';
var myimgarray = myimages.split('|');
function convertImgToBase64(url, callback, outputFormat){
var canvas = document.createElement("canvas");
canvas.width = img.width;
canvas.height = img.height;
var ctx = canvas.getContext("2d");
ctx.drawImage(img, 0, 0);
return canvas.toDataURL("image/jpeg");
var dataURL = canvas.toDataURL("image/jpeg");
callback(dataURL);
canvas = null;
}
for(var i = 0; i < myimgarray.length; i++)
{
icount.count = i;
var img = new Image();
alert(checkoutimgarray);
img.src = '/Portals/0/repair-images/' + myimgarray[i];
img.onload = function(){
newData = convertImgToBase64(img);
alert(newData);
doc.addImage(newData, 'JPEG', (icount * 100), 10, 70, 15); // would doc be undefined here? out of scope?
};
}
doc.setFontSize(20);
doc.text(100, 20, "This is a test to see if images will show");
doc.save('My_file.pdf');
});
});
var canvas = document.createElement("canvas");
var ctx = canvas.getContext("2d");
function convertImgToBase64(img, outputFormat){
// clear canvas
canvas.width = img.width;
canvas.height = img.height;
// draw image
ctx.drawImage(img, 0, 0);
// get data url of output format or defaults to jpeg if not set
return canvas.toDataURL("image/" + (outputFormat || "jpeg"));
}
var images = [];
for(var i = 0; i < myimgarray.length; i++) {
var img = new Image();
img.onload = function() {
images.push({
base64: convertImgToBase64(this),
width: this.width,
height: this.height
});
// all images loaded
if(images.length === myimgarray.length) {
for(var j = 0; j < images.length; j++) {
doc.addImage(images[j].base64, 'JPEG', (j * 100), 10, 70, 15);
}
doc.setFontSize(20);
doc.text(100, 20, "This is a test to see if images will show");
doc.save('My_file.pdf');
}
};
img.src = '/Portals/0/repair-images/' + myimgarray[i];
}

draw array of images to the canvas

I am trying to draw an array of images to the canvas element, my data:image is returning an empty image.
var imgArray = ['images/image1.png','images/image2.png'];
for(i = 0; i < 2; i++){
var canvas = document.getElementById('textCanvas');
var context = canvas.getContext("2d");
var imageObj = new Image();
imageObj.setAtX = i * 10;
imageObj.setAtY = i * 10;
imageObj.onload = function() {
context.drawImage(this, this.setAtX, this.setAtY);
};
}
img = canvas.toDataURL("image/png");
You never set the images' source:
var imageObj = new Image();
imageObj.src = imgArray[i]; // << addeed
imageObj.setAtX = i * 10;
imageObj.setAtY = i * 10;
imageObj.onload = function() {
context.drawImage(this, this.setAtX, this.setAtY);
};

Categories