Javascript for loop, wait for function callback - javascript

I have a for loop that calls a function inside of itself. The function has a callback, however the for loop does not wait for it to finish and continues working.
The for loop actually finishes so quickly that the next action, serving a document that was supposed to be populated inside the for loop, is done before the first function call is completed.
Here is the content of the call I'm actually using, where images is an array holding external URLs to images:
// New jsPDF Document
var doc = new jsPDF();
doc.setFontSize(12);
// For each image we add the image to the document as an image
for (var index = 0; index < images.length; index++) {
// We only add pages after the first one
if (index !== 0) {
doc.addPage();
}
// This puts the URL of the active element at the top of the document
doc.text(35, 25, images[index].path);
// Call to our function, this is the 'skipped' portion
convertImgToDataURLviaCanvas(images[index].path, function(base64Img) {
console.log('An image was processed');
doc.addImage(base64Img, 15, 40, 180, 180);
});
}
doc.save('demo.pdf');
console.log('Document served!');
We get the image URLs from our array, and add everything. The convertImgToDataURLviaCanvas function is here:
// Gets an URL and gives you a Base 64 Data URL
function convertImgToDataURLviaCanvas(url, callback, outputFormat){
var img = new Image();
img.crossOrigin = 'Anonymous';
img.onload = function() {
var canvas = document.createElement('CANVAS');
var ctx = canvas.getContext('2d');
var dataURL;
canvas.height = this.height;
canvas.width = this.width;
ctx.drawImage(this, 0, 0);
dataURL = canvas.toDataURL(outputFormat);
callback(dataURL);
canvas = null;
};
img.src = url;
}
In the former examples even the line doc.text(35, 25, images[index].path); does properly write the URLs to the top of the page. Since that is contained in the array and works along the iterator. However, the for loop is completely done before the first image has been added to our document!
With the console.log you would see: 'Document served!' before the first 'An image was processed'. The goal would be for it to be reversed, with every 'An image was processed' being outputted before Document served! appeared.
How can I achieve this functionality?

To guarantee the order of images, using promises is simple
var promises = images.map(function(image, index) {
return new Promise(function(resolve) {
convertImgToDataURLviaCanvas(image.path, function(base64Img) {
resolve(base64Img);
});
});
}
Promise.all(promises).then(function(results) {
results.forEach(function(base64Img, index) {
if (index !== 0) {
doc.addPage();
}
doc.text(35, 25, images[index].path);
console.log('An image was processed');
doc.addImage(base64Img, 15, 40, 180, 180);
});
doc.save('demo.pdf');
console.log('Document served!');
});
For completeness (unchecked though) - the non promise way to guarantee image order and have the addPage/text in the correct place
var base64 = new Array(images.length); // base64 images held here
images.forEach(function(image, index) {
// Call to our function, this is the 'skipped' portion
convertImgToDataURLviaCanvas(image.path, function(base64Img) {
console.log('An image was processed');
// We only add pages after the first one
base64[index] = base64Img;
done++;
if (done == images.length) {
base64.forEach(function(img64, indx) {
if (indx !== 0) {
doc.addPage();
}
// This puts the URL of the active element at the top of the document
doc.text(35, 25, images[indx].path);
doc.addImage(img64, 15, 40, 180, 180);
}
doc.save('demo.pdf');
console.log('Document served!');
}
});
}
One way to do it is as follows
var done = 0; // added this to keep counf of finished images
for (var index = 0; index < images.length; index++) {
// We only add pages after the first one
if (index !== 0) {
doc.addPage();
}
// This puts the URL of the active element at the top of the document
doc.text(35, 25, images[index].path);
// Call to our function, this is the 'skipped' portion
convertImgToDataURLviaCanvas(images[index].path, function(base64Img) {
console.log('An image was processed');
doc.addImage(base64Img, 15, 40, 180, 180);
// added this code, checks number of finished images and finalises the doc when done == images.length
done++;
if (done == images.length) {
// move the doc.save here
doc.save('demo.pdf');
console.log('Document served!');
}
// end of new code
});
}
Using promises, it's easy as ...
// For each image we add the image to the document as an image
var promises = images.map(function(image, index) {
// We only add pages after the first one
if (index !== 0) {
doc.addPage();
}
// This puts the URL of the active element at the top of the document
doc.text(35, 25, image.path);
// Call to our function, this is the 'skipped' portion
// this returns a Promise that is resolved in the callback
return new Promise(function(resolve) {
convertImgToDataURLviaCanvas(image.path, function(base64Img) {
console.log('An image was processed');
doc.addImage(base64Img, 15, 40, 180, 180);
resolve(index); // doesn't really matter what is resolved
});
});
}
Promise.all(promises).then(function(results) {
doc.save('demo.pdf');
console.log('Document served!');
});

Related

Loading styles from firebase firestore onto canvas error

I am trying to get data from my firestore database and use that data to create a canvas. My goal is to load a set of images and maps to return several canvases.
I am constantly getting this error:
Uncaught (in promise) TypeError: Cannot read property 'getContext' of null
I have tried using setTimeout()'s to delay the speed to help the data load quicker, but nothing seems to work.
var gImgObj;
var gMeme = [];
var gCtx;
var canvas;
function memeDivGet(theId){
setTimeout(function(){
db.collection("memeInfo").where("creator", "==", theId)
.get()
.then(function(querySnapshot) {
querySnapshot.forEach(function(doc) {
db.collection("memeInfo").doc(doc.id).collection("MIMG")
.get()
.then(function(querySnapshot) {
querySnapshot.forEach(function(doc) {
//alert(doc.data())
// alert("here")
console.log(doc.data().Coordinates[0].fontSize)
gMeme.push(doc.data().BaseIMG)
for (var i = 0; i < doc.data().Coordinates.length; i++) {
// alert("here" + i)
gMeme.push({
line: "line",
size: doc.data().Coordinates[i].fontSize,
align: doc.data().Coordinates[i].align,
color: doc.data().Coordinates[i].color, // in color picker, if choosing color from platte notice it stays "solid".
fontFamily: doc.data().Coordinates[i].fontStyle,
lineWidth: 2, // outline width
x: doc.data().Coordinates[i].xPos,
y: doc.data().Coordinates[i].yPos,
text: doc.data().Text[i]
})
}
//console.log(doc.data().BaseIMG)
initCanvas(doc.data().BaseIMG);
})
})
})
})
},1500)
}
function initCanvas(link) {
var canvas = document.querySelector('#canvasImage');
gCtx = canvas.getContext('2d');
gImgObj = new Image();
// console.log(link)
//alert(gMeme[0])
gImgObj.src = link;
gImgObj.onload = function () {
canvas.width = gImgObj.width;
canvas.height = gImgObj.height;
drawCanvas();
};
//console.log("HERE4")
}
function drawCanvas() {
//alert(gMeme)
gCtx.drawImage(gImgObj, 0, 0);
for (var i = 0; i < gMeme.length; i++) {
if(i > 1){
drawTxt(gMeme[i]);
}
}
for (var i = 0; i < gMeme.length - 1; i++) {
drawTxt(gMeme[i + 1]);
}
// gMeme.txts.forEach(function (txt) {
// drawTxt(txt);
// });
}
function drawTxt(txt) {
gCtx.font = txt.size + 'px' + ' ' + txt.fontFamily;
gCtx.textAlign = txt.align;
gCtx.fillStyle = txt.color;
gCtx.fillText(txt.text, txt.x, txt.y);
}
What I want to return is a set of canvases with the parameters I want.
My database is set up in this way for this section of the code:
(fooIds meaning a random id set by firebase)
Collection 'MemeInfo'
Document (fooIds)
SubCollection 'MIMG'
Document 'A'
Inside Each fooId Document, there is a creatorId which helps the computer find who created this meme, I use this to locate the document I am supposed to use for this particular creator's account.
"gMeme" is an array containing information from the database.
An "A Document" has a BaseIMG (the background image), a coordinates array with maps inside (containing the size, color, fontFamily, and other parameters), and a text array with strings inside. There is an image of an "A Document" attached.
I understand that this is quite confusing so if you have any questions please ask them in the comments section.

Changing images using delays

I’m trying to figure out how to make an animation using the order of three images.
The default image is “image1.png” that always shows when the page loads.
After every 5 seconds, the variable “back.src” must abruptly change
to image2.png, so without fading. The default is image1.png
And then after 0.5 seconds, the variable again changes but then to
image3.png.
0.5 seconds later it changes back to image2.png
and 0.5 later again back to image1.png.
This is to be repeated in a loop because I want to repeat the process again after 5 seconds.
My problem is, I don't know if structuring this code is the best way to go about it. How would my code need to look based on the requirement explained above?
Here's my code of what I've got so far:
var back = new Image();
back.src = "image1.png";
function wait(miliseconds) {
var currentTime = new Date().getTime();
while (currentTime + miliseconds >= new Date().getTime()) {
}
}
function image1() {
wait(5000);
back.src = "image2.png";
}
function image2() {
wait(500);
back.src = "image3.png";
}
function image3() {
wait(500);
back.src = "image2.png";
}
function animate(){
ctx.save();
ctx.clearRect(0, 0, cW, cH);
ctx.drawImage(back,0,0);
ctx.restore();
}
var animateInterval = setInterval(animate, 30);
There is no wait() operation in Javascript and usually trying to make one like you are doing causes bad things to happen (event loops get starved, user interfaces get locked up, etc...). Instead, you schedule things to run in the future with setTimeout(). This allows the JS engine to do other things (like service other events happening in the system) while you are waiting for your next loop iteration and is generally very important in Javascript.
I'd suggest you just put the sequence you want into a data structure and then use a timer that iterates through the data structure, wrapping when it gets to the end:
var data = [
["image1.png", 5000],
["image2.png", 500],
["image3.png", 500],
["image4.png", 500]
];
function runAnimation() {
var index = 0;
function animate(image){
ctx.save();
ctx.clearRect(0, 0, cW, cH);
ctx.drawImage(image,0,0);
ctx.restore();
}
function next() {
var img = new Image();
img.src = data[index][0];
animate(img);
// schedule next iteration
var t = data[index][1];
// increment and wrap index if past end
index = (index + 1) % data.length;
setTimeout(next, t);
}
next();
}
To make this work properly, you will need your images to be precached so they get loaded immediately. If you aren't going to precache the images, then you will need to add onload handlers so you can know when the images have finished loading and are ready for drawing.
There is info on precaching images here: How do you cache an image in Javascript
Or, to make sure your images are loaded before drawing with them, you can use an onload handler like this:
var data = [
["image1.png", 5000],
["image2.png", 500],
["image3.png", 500],
["image4.png", 500]
];
function runAnimation() {
var index = 0;
function animate(image){
ctx.save();
ctx.clearRect(0, 0, cW, cH);
ctx.drawImage(image,0,0);
ctx.restore();
}
function next() {
var img = new Image();
var nextSrc = data[index][0];
img.onload = function() {
animate(img);
// schedule next iteration
var t = data[index][1];
// increment and wrap index if past end
index = (index + 1) % data.length;
setTimeout(next, t);
};
img.src = nextSrc;
}
next();
}
You can achieve it using setIterval()
Read about JS Timers Here
Here is what you need : https://jsfiddle.net/nfe81zou/3/
var image1 = "https://pixabay.com/static/uploads/photo/2016/06/17/13/02/duck-1463317_960_720.jpg";
var image2 = "https://pixabay.com/static/uploads/photo/2013/09/22/16/56/duck-185014_960_720.jpg";
var image3 = "https://pixabay.com/static/uploads/photo/2013/11/02/03/23/ducks-204332_960_720.jpg";
$(function() {
$("#image").prop("src", image1);
setInterval(function() {
$("#image").prop("src", image2);
setTimeout(function() {
$("#image").prop("src", image1);
setTimeout(function() {
$("#image").prop("src", image3);
}, 500);
setTimeout(function() {
$("#image").prop("src", image2);
}, 1000);
}, 1500);
}, 5000);
});
#image {
border: 2px solid red;
width: 400px;
height: 200px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<img src="" id="image"/>
This would be my approach on this problem. The images are displayed in the order of
0 (5000ms) -> 1 (500ms) -> 2 (500ms) -> 1 (500ms) -> 0 (5000ms) ...
There is no setInterval() here. This code utilizes a pseudo recursive setTimeout() implementation.
var images = ["http://1.bp.blogspot.com/_ZRj5nlc3sp8/S-T7vOsypQI/AAAAAAAADBo/0kYfB8BM6zE/s320/beautiful+girl+pics+1.jpg",
"http://1.bp.blogspot.com/-w4UtHwbrqBE/ViNbJWhnmvI/AAAAAAAADtY/hGbRtz993Tg/s1600/face%2Bwallpapers%2B%25282%2529.jpg",
"http://2.bp.blogspot.com/-4kZ9Iu8QTws/ViNbL3S29fI/AAAAAAAADtw/QakqQE72N1w/s1600/face%2Bwallpapers%2B%25286%2529.jpg"],
imel = document.getElementById("photo");
function displayImages(idx,fwd){
var ms = 0;
idx = idx || 0; // we could also use the ES6 default value method.
if (idx === 0) {
fwd = !fwd; // when index becomes 0 switch the direction of the loop
ms = fwd ? 5000 // if backwards rearrange index and duration to 0.5 sec
: (idx = images.length - 2, 500);
} else ms = 500; // when index is not 0 set the duration to 0.5 sec
imel.src = images[idx];
fwd ? setTimeout(function(){displayImages(++idx % images.length,fwd)},ms)
: setTimeout(function(){displayImages(--idx,fwd)},ms);
}
displayImages();
<image id ="photo"></image>

Saving multiple SVGs to canvas with text then getting dataURL

I have built an angularJS application, in this application SVG files represent garments that a user chooses. I have a download button which (currently) saves the first SVG as a PNG into a database and I use a view to display this "preview".
The directive I created looks like this:
.directive('kdExport', function () {
return {
restrict: 'A',
scope: {
target: '#kdExport',
team: '='
},
controller: 'ExportImageController',
link: function (scope, element, attrs, controller) {
console.log(scope.team);
// Bind to the onclick event of our button
element.bind('click', function (e) {
// Prevent the default action
e.preventDefault();
// Generate the image
controller.generateImage(scope.target, scope.team, function (preview) {
// Create our url
var url = '/kits/preview/' + preview.id;
// Open a new window
window.open(url, '_blank');
});
});
}
};
})
and the controller looks like this:
.controller('ExportImageController', ['PreviewService', function (service) {
var self = this;
// Function to remove the hidden layers of an SVG document
var removeHidden = function (element) {
// Get the element children
var children = element.children(),
i = children.length;
// If we have any children
if (children.length) {
// For each child
for (i; i >= 0; i--) {
// Get our child
var child = angular.element(children[i - 1]);
// Remove hidden from the child's children
removeHidden(child);
// Finally, if this child has the class "hidden"
if (child.hasClass("hidden")) {
// Remove the child
child.remove();
}
}
}
};
// Public function to generate the image
self.generateImage = function (element, team, onSuccess) {
// Get our SVG
var target = document.getElementById(element),
container = target.getElementsByClassName('svg-document')[0],
clone = container.cloneNode(true);
// Remove hidden layers
removeHidden(angular.element(clone));
// Create our data
var data = clone.innerHTML,
svg = new Blob([data], { type: 'image/svg+xml;charset=utf-8' });
// Get our context
var canvas = document.getElementById('canvas'),
ctx = canvas.getContext('2d');
// Create our image
var DOMURL = window.URL || window.webkitURL || window,
url = DOMURL.createObjectURL(svg),
img = new Image();
// When the image has loaded
img.onload = function () {
canvas.width = 1000;
canvas.height = 500;
// Draw our image using the context
ctx.drawImage(img, 0, 0, img.width, img.height, 0, 0, 1000, 500);
DOMURL.revokeObjectURL(url);
// Get our URL as a base64 string
var dataURL = canvas.toDataURL("image/png");
// Create our model
var model = {
teamName: team.name,
sport: team.sport,
data: dataURL
};
// Create our preview
service.create(model).then(function (response) {
// Invoke our success callback
onSuccess(response);
});
}
// Set the URL of the image
img.src = url;
};
}])
This works fine for a single SVG document, but now the client has asked me to do this for multiple SVGs with a title under each one and they want it all in one PNG.
I have not done a lot of work with canvasing, so I am not sure if this can be done.
Does anyone know how I might achieve this?
Ok, so I figured this out myself using promises.
Basically I created a method called drawImage that allowed me to draw an image for each SVG.
To make sure that all images were drawn before I invoke toDataURL I made the function return a promise and once the image loaded I resolved that promise.
Then I just used a $q.all to get the dataURL and save the data to my database.
The methods looked like this:
// Private function for drawing our images
var drawImage = function (canvas, ctx, clone) {
// Defer our promise
var deferred = $q.defer();
// Create our data
var data = clone.innerHTML,
svg = new Blob([data], { type: 'image/svg+xml;charset=utf-8' });
// Create our image
var DOMURL = window.URL || window.webkitURL || window,
url = DOMURL.createObjectURL(svg),
img = new Image();
// When the image has loaded
img.onload = function () {
// Get our location
getNextLocation(canvas.width, canvas.height, img);
// Draw our image using the context (Only draws half the image because I don't want to show the back)
ctx.drawImage(img, 0, 0, img.width / 2, img.height, location.x, location.y, location.width, location.height);
DOMURL.revokeObjectURL(url);
// Resolve our promise
deferred.resolve();
}
// Set the URL of the image
img.src = url;
// Return our promise
return deferred.promise;
};
// Public function to generate the image
self.generateImage = function (element, team, onSuccess) {
// Get our SVG
var target = document.getElementById('totals'),
containers = angular.element(target.getElementsByClassName('svg-document'));
// Get our context
var canvas = document.getElementById('canvas'),
ctx = canvas.getContext('2d');
// Set our canvas height and width
canvas.width = 2000;
canvas.height = calculateCanvasHeight(containers.length);
// Create our array of promises
var promises = [];
// For each container
for (var i = 0; i < containers.length; i++) {
// Get our container
var container = containers[i],
clone = container.cloneNode(true);
// Remove hidden layers
removeHidden(angular.element(clone));
// Add our promise to the array
promises.push(drawImage(canvas, ctx, clone));
}
// When all promises have resolve
$q.all(promises).then(function () {
// Get our URL as a base64 string
var dataURL = canvas.toDataURL("image/png");
// Create our model
var model = {
teamName: team.name,
sport: team.sport,
data: dataURL
};
// Create our preview
self.create(model).then(function (response) {
// Invoke our success callback
onSuccess(response);
});
})
};
Obviously there is missing code here, but this code answers my issue, the rest just makes my service work :)

Html2canvas for each div export to pdf separately

I have Page, It has 6 div with same class name "exportpdf", I am converting those div into pdf using jspdf and html2canvas
var elementTobePrinted = angular.element(attrs.selector),
iframeBody = elementTobePrinted.contents().find('div.exportpdf');
In html2canvas.....
html2canvas(elementTobePrinted, {
onrendered: function (canvas) {
var doc = new jsPDF();
for(var i=1;i<elementTobePrinted.length;i++){
doc.addImage(canvas.toDataURL("image/jpeg"), 'jpeg', 15, 40, 180, 160);
doc.addImage(canvas.toDataURL("image/jpeg"),'JPEG', 0, 0, 215, 40)
doc.addPage();
}
doc.save(attrs.fileName);
}
I converted page to canvas.its create same div contents for whole pdf. I need each div contents into same pdf with different pages.
Can anyone help me?
The problem is with html2canvas:
doc.addImage(canvas.toDataURL("image/jpeg"), 'jpeg', 15, 40,180, 160);
Here I need to pass elementTobePrinted list to addImage.
On angular 2(now 6) framework.
u can use the logic as below,
On click execute generateAllPdf() function,
gather all 6 id's from my html collection,
iterate through each id and call html2canvas function,
as html2canvas runs in background to process images, i m using
await on function,
after the html2canvas completes its process, i ll save the
document,
If suppose i wont use await i ll end-up in downloading an empty
page.
below is my code logic,
// As All Functions in js are asynchronus, to use await i am using async here
async generateAllPdf() {
const doc = new jsPDF('p', 'mm', 'a4');
const options = {
pagesplit: true
};
const ids = document.querySelectorAll('[id]');
const length = ids.length;
for (let i = 0; i < length; i++) {
const chart = document.getElementById(ids[i].id);
// excute this function then exit loop
await html2canvas(chart, { scale: 1 }).then(function (canvas) {
doc.addImage(canvas.toDataURL('image/png'), 'JPEG', 10, 50, 200, 150);
if (i < (length - 1)) {
doc.addPage();
}
});
}
// download the pdf with all charts
doc.save('All_charts_' + Date.now() + '.pdf');
}
I think the issue here is that elementTobePrintedis not what you think it is.
When you run the code:
var elementTobePrinted = angular.element(attrs.selector)
This will return you a list of every element that matches the conditions, so you said you have 6 of these elements ("It has 6 divs").
Have you tried replacing:
html2canvas(elementTobePrinted, {
onrendered: function (canvas) {
var doc = new jsPDF();
for(var i=1;i<elementTobePrinted.length;i++) {
doc.addImage(canvas.toDataURL("image/jpeg"), 'jpeg', 15, 40, 180, 160);
doc.addImage(canvas.toDataURL("image/jpeg"),'JPEG', 0, 0, 215, 40)
doc.addPage();
}
doc.save(attrs.fileName);
}
With...
for(var i=0; i<elementTobePrinted.length; i++){
html2canvas(elementTobePrinted[i], {
onrendered: function (canvas) {
var doc = new jsPDF();
doc.addImage(canvas.toDataURL("image/jpeg"), 'jpeg', 15, 40, 180, 160);
doc.addImage(canvas.toDataURL("image/jpeg"),'JPEG', 0, 0, 215, 40)
doc.addPage();
doc.save(attrs.fileName);
}
}
The reason I suggest this is that html2Canvas wants a SINGLE element as its first parameter and your example above passes a list of elements (I think, assuming angular.element(attrs.selector) finds all 6 divs you are trying to print).

Kineticjs Object Handling & Event Listener

I sell custom equipment and on my site, I have a flash tool where customers can assign colors to glove parts and see what it will look like.
I've been working on a HTML5 version of this tool, so the iPad crowd can do the same thing. Click here for what I've done,
I took kineticjs multiple picture loader and hacked it to load all the pics necessary to stage and the color buttons, which are multiple instances of the same image. In their example, it was only 2 images, so they var name each image, which were manipulative. My goal is to dynamically create variable, based on image name.
I'm using a for loop and if statements to position the parts according to their type. If the image being loaded is a button, the original instance is not added to the stage, but another for loop, with a counter, creates instances and put on the stage. The variable is part string+n (wht0). From here I initiate an eventlistener, when clicked is suppose to hide all glove parts pertaining to the option and show the appropriate color. That code I have already in my AS.
I created an eventlistener on the white buttons (first button) that when clicked, I set it to hide one of the white leather part of glove. But when I click the button, I get the error in console that the glove part (ex wlt_wht), I get an error stating that the object is not defined. But when the image was loaded the variable name came from the current array object being loaded.
I added another variable before the callback call, to convert the content of the array to a string and used the document.write to confirm that the object name is correct, but after creating the object its now [object object]. In flash, you manually assign the movie clip name and target.name is available if you call it.
How can I write the Image obj so I can control the object? In the doc there is a reference for id and name as properties of the object, but when I set these, it did not work with me. Sure, I could have manually created each Kinetic.Image(), but there's no fun in that.. especially with 191 images. Any tip on how I can get around this problem?
Checkout http://jsfiddle.net/jacobsultd/b2BwU/6/ to examine and test script.
function loadImages(sources, callback) {
var assetDir = 'http://dev.nystixs.com/test/inf/';
var fileExt = '.png';
var images = {};
var loadedImages = 0;
var numImages = 0;
for (var src in sources) {
numImages++;
}
for (var src in sources) {
images[src] = new Image();
images[src].onload = function () {
var db = sources[src].toString();
var dbname = db.slice(-0, -4);
if (++loadedImages >= numImages) {
callback(images, dbname);
}
};
images[src].src = assetDir + sources[src];
//images[src].src = assetDir+sources[src]+".png";
}
}
function initStage(images, db) {
var shapesLayer = new Kinetic.Layer();
var messageLayer = new Kinetic.Layer();
//Loading Images
var xpos = 0;
var ypos = 200;
for (var i in images) {
var glvP = i.slice(0, 3);
db = new Kinetic.Image({
image: images[i],
x: xpos,
y: ypos
});
if (glvP == "wlt") {
shapesLayer.add(db);
db.setPosition(186.95, 7.00);
//db.hide();
shapesLayer.draw();
} else if (glvP == "lin") {
shapesLayer.add(db);
db.setPosition(204.95, 205.00);
} else if (glvP == "plm") {
shapesLayer.add(db);
db.setPosition(311.95, 6.00);
} else if (glvP == "web") {
shapesLayer.add(db);
db.setPosition(315.95, 7.00);
} else if (glvP == "lce") {
shapesLayer.add(db);
db.setPosition(162.95, 3.00);
} else if (glvP == "thb") {
shapesLayer.add(db);
db.setPosition(63.00, 28.60);
} else if (glvP == "bfg") {
shapesLayer.add(db);
db.setPosition(167.95, 7.00);
} else if (glvP == "wst") {
shapesLayer.add(db);
db.setPosition(208.95, 234.00);
} else if (glvP == "fpd") {
shapesLayer.add(db);
db.setPosition(252.95, 82.00);
} else if (glvP == "bac") {
shapesLayer.add(db);
db.setPosition(0, 0);
} else if (glvP == "bnd") {
shapesLayer.add(db);
db.setPosition(196.95, 164.00);
} else {}
var rect = new Kinetic.Rect({
x: 710,
y: 6,
stroke: '#555',
strokeWidth: 5,
fill: '#ddd',
width: 200,
height: 325,
shadowColor: 'white',
shadowBlur: 10,
shadowOffset: [5, 5],
shadowOpacity: 0.2,
cornerRadius: 10
});
shapesLayer.add(rect);
// End of Glove Parts Tabs
//Load Color Buttons
if (glvP == "wht") {
xpos = -5.00;
bpos = 375;
var zpos = -5.00;
var tpos = -5.00;
db.setPosition(xpos, bpos);
//shapesLayer.add(db);
var n = 0;
for (n = 0; n < 12; n++) {
if (n < 4) {
var glvB = "wht" + n;
var btn = glvB;
glvB = new Kinetic.Image({
image: images[i],
width: 18,
height: 18,
id: 'wht0'
});
glvB.on('mouseout', function () {
blankText('');
});
glvB.on('mouseover', function () {
writeColors('White', btn);
});
glvB.on('click', function () {
console.log(glvB + " clicked");
wht.hide();
shapesLayer.draw();
});
glvB.setPosition((xpos + 20), bpos);
shapesLayer.add(glvB);
xpos = (xpos + 230);
}
You can use your .png image filenames to automate your color-button coding efforts.
No need to manually code 10 glove components X 21 colors per component (210 color buttons).
Assume you’ve split the each image URL (filename) to get the color and glove-type.
Then you can create all 210 color buttons with one piece of reusable code.
Demo: http://jsfiddle.net/m1erickson/H5FDc/
Example Code:
// Usage:
addColorButton(100,100,"red","fingers");
// 1 function to add 210 color-buttons
function addColorButton(x,y,color,component){
// create this button
var button=new Kinetic.Image({
x:x,
y:y,
image: imageArray[ color+"-color-button" ],
});
// save the color as a property on this button
button.gloveColor=color;
// save the glove component name as a property on this button
button.gloveComponent=component; // eg, "fingers"
// resuable click handler
// Will change the gloves "#fingers" to "red-fingers-image"
button.on("click",function(){
// eg. get the image "red-fingers-image"
var newImage = imageArray[this.gloveColor+"-"+this.gloveComponent+"-image"];
// eg. get the Kinetic.Image with id:”finger”
var glovePart = layer.find("#"+this.gloveComponent”][0];
// change the Kinetic id:finger’s image
// to the red-fingers-image
glovePart.setImage(newImage);
layer.draw();
});
layer.add(button);
}

Categories

Resources