Related
I am from supercoloring and we decided to convert our vector illustrations in color to color by number worksheets. Our input files are color and outline images in svg format.
Outline version (like a coloring page) + Color version
outline version and
color version
What we want to get is the following
result
We would like that a color palette is generated under the outline version of the image based on the color data from the color version of the image. Moreover, numbers corresponding to this palette are placed inside each color space of the outlined version.
I understand that no script in the world would do this properly, but at least I am striving to reduce the time spent by the editor (person) to put these numbers manually in the Illustrator. I understand that our color vector images may have too many colors and shades so we need somehow to limit the result colors of the palette ( to fuse them into large groups of basic colors).
I searched all over the stackoverflow solutions and found some ingenious like Paint with numbers with Adobe Illustrator Javascript and
I'm looking to create an automated numbering system for custom paint by number kits in photoshop (Kudos to Yuri Khristich). However, they are not exactly adapted to our needs.
Most of scripts on the web generate outlined images from color version, but the quality is compromised. We have already a proper outline version that we want to use as a base for color by number worksheet.
Here is the script to make a 'color palette' for selected artwork.
And here, as you know, is the script to add color names to all filled areas.
So I took the two script, made a couple of minimal tweaks and get almost the result you want. All you need after the scripts is to copy the layer with numbers and 'palette' from a colored artwork to a outline version.
Script #1
// Modified version
// https://stackoverflow.com/questions/75344674/paint-by-number-illustrator-script
// Original:
// https://productivista.com/make-a-list-of-colors-from-your-selection/
/*
Date: July, 2020
Author: Katja Bjerrum, email: katja#productivista.com, www.productivista.com
============================================================================
NOTICE:
This script is provided "as is" without warranty of any kind.
Free to use, not for sale.
============================================================================
Released under the MIT license.
http://opensource.org/licenses/mit-license.php
============================================================================
*/
//#target illustrator
var doc = app.activeDocument;
var myLayer = doc.activeLayer;
app.coordinateSystem = CoordinateSystem.ARTBOARDCOORDINATESYSTEM;
var swGrps = doc.swatchGroups;
var mainSwGr = doc.swatchGroups[0];
var sel = doc.selection;
var actionSet = 'CreateSwatchGroup';
var actionName = 'ColourGroup';
var actionPath = Folder.myDocuments + '/Adobe Scripts/';
if (!Folder(actionPath).exists) Folder(actionPath).create();
//app.doScript("Colorgroup", "ToSwatchScript"); // Action, that creates swatch group
var actionDoc =
[ '/version 3',
'/name [' + actionSet.length + ' ' + ascii2Hex(actionSet) + ']',
'/isOpen 1',
'/actionCount 1',
'/action-1 {',
'/name [' + actionName.length + ' ' + ascii2Hex(actionName) + ']',
' /keyIndex 0',
' /colorIndex 0',
' /isOpen 1',
' /eventCount 1',
' /event-1 {',
' /useRulersIn1stQuadrant 0',
' /internalName (ai_plugin_swatches)',
' /localizedName [ 8',
' 5377617463686573',
' ]',
' /isOpen 0',
' /isOn 1',
' /hasDialog 1',
' /showDialog 1',
' /parameterCount 1',
' /parameter-1 {',
' /key 1835363957',
' /showInPalette 4294967295',
' /type (enumerated)',
' /name [ 15',
' 4e657720436f6c6f722047726f7570',
' ]',
' /value 17',
' }',
' }',
'}'].join('');
createAction(actionDoc, actionName, actionPath);
app.redraw();
app.doScript (actionName, actionSet);
app.redraw();
app.unloadAction(actionSet, '');
var convMM = 2.8346456692; // initialization of the variable to convert points to mm
var colorgroup = doc.swatchGroups[doc.swatchGroups.length - 1]; // Choose the last swatch group
var stY = -200; //
var stX = 20;
var recW = 25;
var recH = 25;
var offX = recW / 5;
var offY = recH / 4;
var textoffY = recH / 4;
var rows = 4;
var cols = 4;
var black = new GrayColor();
black.gray = 80;
var white = new GrayColor() ;
white.gray = 0;
var noStroke = doc.swatches[0].color;
if (swGrps.length <=1){
alert ("Please create swatch group from your selection");
}
else if (sel <= 0){
//docRef.placedItems[0].selected == false;
alert ("Please make a selection");
delSwatchGr(colorgroup); //delete swatch group
}
else{
swatchGroupList(colorgroup, stY, stX);//create corlor list
// delSwatchGr(colorgroup);//delete swatch group
}
//Function, that creates color list
function swatchGroupList(swatchGroup, stY, stX) {
// Groups everything in the list
var mainGroup = myLayer.groupItems.add();
mainGroup.name = "Colors";
mainGroup.moveToBeginning(myLayer);
//Name of the color list
var nameText = myLayer.textFrames.add();
nameText.contents = swatchGroup.name; // the name of the swatch group
nameText.position = [stX, stY + recH];
var nameStyle = nameText.textRange.characterAttributes;
nameStyle.size = 12;//size in punkt
//nameStyle.textFont = textFonts.getByName("Avenir-Book");//the font
nameStyle.capitalization = FontCapsOption.ALLCAPS;//ALL CAPITALS
var swatches = swatchGroup.getAllSwatches();
var swatchArray = [];
for (i = swatches.length-1; i>=0; i--) {
var mySwatch = swatches[i];
mySwatch.name = i + 1;
var subGroup = createSwatchGroup(mySwatch, textoffY);
swatchArray.push(subGroup);
}
nameText.moveToEnd(mainGroup);
var myGroup = swatchArray;
var maxW = maxWidth(myGroup);
for (var j = 0; j < myGroup.length; j++) {
var mySubGroup = myGroup[j];
mySubGroup.moveToBeginning(mainGroup);
}
for (var i = 0; i < mainGroup.groupItems.length; i++) {
var mySubGroup = mainGroup.groupItems[i];
if (mainGroup.groupItems.length > 7) {
rows = 7;
var c = i%rows;
var r = Math.floor(i/rows);
mySubGroup.position = [stX + r * (maxW + 10), stY - c * (recH + offY)];
}
else {
rows = 7;
var c = i % rows;
var r = Math.floor(i / rows);
mySubGroup.position = [stX, stY - c * (recH + offY)];
}
}
// textSwatch.moveToBeginning(SubGroup);
// path_ref.moveToBeginning(SubGroup);
// SubGroup.position = [stX + c * 140, stY - r * (path_ref.height + offY)];
subGroup.moveToBeginning(mainGroup);
}
function lightColor(c){
if(c.typename)
{
switch(c.typename)
{
case "CMYKColor":
return (c.black>=10 || c.cyan>10 || c.magenta>10 || c.yellow > 10) ? true : false;
case "RGBColor":
return (c.red<230 || c.green<230 || c.blue<230) ? true : false;
case "GrayColor":
return c.gray >= 10 ? true : false;
case "SpotColor":
return lightColor(c.spot.color);
//return false;
}
}
}
function fitItem(item, itemW, itemH, diff) {
var oldWidth = item.width
var oldHeight = item.height
if (item.width > item.height) {
// landscape, scale height using ratio from width
item.width = itemW - diff.deltaX
var ratioW = item.width / oldWidth
item.height = oldHeight * ratioW
} else {
// portrait, scale width using ratio from height
item.height = itemH - diff.deltaY
var ratioH = item.height / oldHeight
item.width = oldWidth * ratioH
}
}
function itemBoundsDiff(item) {
var itemVB = item.visibleBounds
var itemVW = itemVB[2] - itemVB[0] // right - left
var itemVH = itemVB[1] - itemVB[3] // top - bottom
var itemGB = item.geometricBounds
var itemGW = itemGB[2] - itemGB[0] // right - left
var itemGH = itemGB[1] - itemGB[3] // top - bottom
var deltaX = itemVW - itemGW
var deltaY = itemVH - itemGH
var diff = { deltaX: deltaX, deltaY: deltaY }
return diff
}
function delSwatchGr(swGr){
var swGrSws = swGr.getAllSwatches();
for (var j = 0; j < swGrSws.length; j++){
var sw = swGrSws[j];
sw.color = new CMYKColor();
}
swGr.remove();
}
//Function finds the max group width
function maxWidth(myGroup) {
var maxFound = 0;
for (var j = 0; j < myGroup.length; j++) {
var GrWidth = myGroup[j].width;
//var Widthmax = GrWidth.width;
maxFound = Math.max(maxFound, GrWidth);
}
return maxFound;
}
function createSwatchGroup(sw, myOffset) {
//Is "MyForm" path exists?
try{
var path_ref_ori = app.activeDocument.pathItems.getByName("MyForm" || "myform" || "MYFORM");
}
catch(e) {
var path_ref_ori = false;
}
if (path_ref_ori) {
myPath = path_ref_ori.duplicate();
var boundsDiff = itemBoundsDiff(myPath);
fitItem(myPath, recW, recH, boundsDiff);
myPath.name = "NewForm";
myPath.position = [0, 0];
}
else {
var myPath = createMyPath()
}
myPath.fillColor = sw.color;
myPath.stroked = true;
myPath.strokeWidth = 0.3;
myPath.strokeColor = lightColor(myPath.fillColor) ? noStroke : black;
var textSwatch = myLayer.textFrames.add(); //swatch text
textSwatch.contents = sw.name;
textSwatch.position = [myPath.width + 1.3 * convMM, -myOffset];
var textSwStyle = textSwatch.textRange.characterAttributes;
textSwStyle.size = 10; //size in punkt
//textSwStyle.textFont = textFonts.getByName("MyriadPro-Semibold"); //the font
var SubGroup = myLayer.groupItems.add(); //groups path and text
SubGroup.name = sw.name;
SubGroup.position = [0, 0];
textSwatch.moveToBeginning(SubGroup);
myPath.moveToBeginning(SubGroup);
return SubGroup;
}
function createMyPath(){
//Is "MyForm" path exists?
try{
var path_ref_ori = app.activeDocument.pathItems.getByName("MyForm" || "myform" || "MYFORM");
}
catch(e) {
var path_ref_ori = false;
}
if (path_ref_ori) {
path_ref = path_ref_ori.duplicate();
var boundsDiff = itemBoundsDiff(path_ref);
fitItem(path_ref, recW, recH, boundsDiff);
path_ref.name = "NewForm";
path_ref.position = [0, 0];
}
else {
var path_ref = myLayer.pathItems.rectangle(0, 0, recW, recH); //swatch path item
}
return path_ref
};
function createAction(str, set, path) {
var f = new File('' + path + '/' + set + '.aia');
f.open('w');
f.write(str);
f.close();
app.loadAction(f);
f.remove();
};
function ascii2Hex(hex) {
return hex.replace(/./g, function (a) { return a.charCodeAt(0).toString(16) });
};
Input (after select the artwork and run the script):
Result (added the global swatches and the 'color palette' at the bottom):
Script #2
// Based on:
// https://stackoverflow.com/questions/73705368/paint-with-numbers-with-adobe-illustrator-javascript
var doc = app.activeDocument,
lays = doc.layers,
WORK_LAY = lays.add(),
NUM_LAY = lays.add(),
i = lays.length - 1,
lay;
// main working loop
for (; i > 1; i--) {
//process each layer
lay = lays[i];
lay.name = lay.name + " Num:" + (i - 1); // i-1 as 2 layers beed added.
process(lay.pathItems, false);
process(lay.compoundPathItems, true); // if any
}
//clean up
NUM_LAY.name = "Numbers";
WORK_LAY.remove();
function process(items, isCompound) {
var j = 0,
b, xy, s, p, op;
for (; j < items.length; j++) {
// process each pathItem
op = items[j];
try { color = op.fillColor.spot.name } catch(e) { continue } // <-- HERE
// add stroke
if (isCompound) {
// strokeComPath(op);
} else {
// !op.closed && op.closed = true;
// op.filled = false;
// op.stroked = true;
};
b = getCenterBounds(op);
xy = [b[0] + (b[2] - b[0]) / 2, b[1] + (b[3] - b[1]) / 2];
s = (
Math.min(op.height, op.width) < 20 ||
(op.area && Math.abs(op.area) < 150)
) ? 20 : 40; // adjust font size for small area paths.
add_nums(color, xy, s); // <--- HERE
}
}
function getMinVisibleSize(b) {
var s = Math.min(b[2] - b[0], b[1] - b[3]);
return Math.abs(s);
}
function getGeometricCenter(p) {
var b = p.geometricBounds;
return [(b[0] + b[2]) / 2, (b[1] + b[3]) / 2];
}
// returns square of distance between p1 and p2
function getDist2(p1, p2) {
return Math.pow(p1[0] + p2[0], 2) + Math.pow(p1[1] + p2[1], 2);
}
// returns visibleBounds of a path in a compoundPath p
// which is closest to center of the original path op
function findBestBounds(op, p) {
var opc = getGeometricCenter(op);
var idx = 0,
d;
var minD = getDist2(opc, getGeometricCenter(p.pathItems[0]));
for (var i = 0, iEnd = p.pathItems.length; i < iEnd; i++) {
d = getDist2(opc, getGeometricCenter(p.pathItems[i]));
if (d < minD) {
minD = d;
idx = i;
}
}
return p.pathItems[idx].visibleBounds;
}
function applyOffset(op, checkBounds) {
var p = op.duplicate(WORK_LAY, ElementPlacement.PLACEATBEGINNING),
// offset value the small the better, but meantime more slow.
offset = function() {
var minsize = Math.min(p.width, p.height);
if (minsize >= 50) {
return '-1'
} else if (20 < minsize && minsize < 50) {
return '-0.5'
} else {
return '-0.2' // 0.2 * 2 (both side ) * 50 (Times) = 20
}
},
xmlstring = '<LiveEffect name="Adobe Offset Path"><Dict data="I jntp 2 R mlim 4 R ofst #offset"/></LiveEffect>'
.replace('#offset', offset()),
TIMES = 100; // if shapes are too large, should increase the value.
if (checkBounds) {
// check its size only if it needs, because it's too slow
while (TIMES-- && getMinVisibleSize(p.visibleBounds) > 3) p.applyEffect(xmlstring);
} else {
while (TIMES--) p.applyEffect(xmlstring);
}
return p;
}
function getCenterBounds(op) {
var originalMinSize = getMinVisibleSize(op.visibleBounds);
var p = applyOffset(op, false);
if (getMinVisibleSize(p.visibleBounds) > originalMinSize) {
// in some cases, path p becomes larger for some unknown reason
p.remove();
p = applyOffset(op, true);
}
var b = p.visibleBounds;
if (getMinVisibleSize(b) > 10) {
activeDocument.selection = [p];
executeMenuCommand("expandStyle");
p = activeDocument.selection[0];
if (p.typename == "CompoundPathItem") {
b = findBestBounds(op, p);
}
}
p.remove();
return b;
}
function add_nums(n, xy, s) {
var txt = NUM_LAY.textFrames.add();
txt.contents = n;
txt.textRange.justification = Justification.CENTER;
txt.textRange.characterAttributes.size = s;
txt.position = [xy[0] - txt.width / 2, xy[1] + txt.height / 2];
}
function strokeComPath(compoundPath) {
var p = compoundPath.pathItems,
l = p.length,
i = 0;
for (; i < l; i++) {
// !p[i].closed && p[i].closed = true;
// p[i].stroked = true;
// p[i].filled = false;
}
};
Result (added the layer with numbers after run the script):
Final outlined version with numbers and the 'color palette'
Note: you have to ungroup and unmask the color artwork before you run the Script #2.
Here is the results for the rest examples:
As you can see the 'final' artwork still need a quite amount of additional manual work: to move or remove extra numbers.
And it makes sense to reduce the number of colors in original color artworks (perhaps it's possible to do with a script to some extent, as well).
I am currently working in GAS to create and optimize a search function based on multiple criteria.
I have code that works, but it is inconsistent on whether or not the function call will time-out before the search is completed.
//Top level function to run the sub-level OD, ID, End Ring, Pusher, and Bushing Length functions
function toolSearch(od, id, mat) {
var od1 = parseFloat(od);
var id1 = parseFloat(id);
var inc = .25; //change to 0 when standardized bushings are implemented
var passOutput = [];
var failOutput = ["Tooling Unavailable", "Contact CPI Stafford Materials Engineer"];
if (od1 > 49 || id1 > 46)
return failOutput;
//If statement to determine amount of end rings required based on OD shell size and material
if (mat == "Hot Mold" && od < 10)
var qER = 4;
else
qER = 2;
//Initial tooling search
var od2 = toolSearchOD(od1);
var id2 = toolSearchID(id1);
var er = toolSearchER(od2, id2);
var ps = toolSearchPS(od2);
var wall = wallCall(od2, id2);
//return variables must be parsed from strings to integers and decimals
od2 = parseFloat(od2);
id2 = parseFloat(id2);
er = parseInt(er);
ps = parseInt(ps);
wall = parseFloat(wall);
//Remove comments when standardized bushings are implemented
/*if(id>10)
{inc = .5;}
else
{inc = .25;}*/
//If statement to check for pusher and end ring requirments before moving into for loop
if (er < qER || ps < 1) {
//For loop to find OD and ID shells, the required quantity of end rings, and the pusher
for (var i = 0; i < 50; i++) { //Loop is set at 75 in order to prevent 30 second function time out. May need to be adjusted.
od2 += inc;
od2 = toolSearchOD(od2);
od2 = parseFloat(od2);
wall = wallCall(od2, id2);
wall = parseFloat(wall);
er = toolSearchER(od2, id2);
er = parseInt(er);
ps = toolSearchPS(od2);
ps = parseInt(ps);
if (wall > 3) {
id2 -= inc
id2 = toolSearchID(id2);
id2 = parseFloat(id2);
od2 = od1 - inc;
od2 = parseFloat(od2);
er = toolSearchER(od2, id2);
er = parseInt(er);
}
if (er >= qER && ps >= 1)
break;
}
}
//A final check to make sure that the variable is parsed to an integer or decimal
od2 = parseFloat(od2);
id2 = parseFloat(id2);
er = parseInt(er);
ps = parseInt(ps);
wall = parseFloat(wall);
var blength = bLength(mat, od2, id2); //Bushing Length function input/output
//If statement to check if requirements have been met to return the proper information
if (er < qER || ps < 1 || wall > 3) {
return failOutput;
} else {
passOutput = [od2, id2, blength, er, ps, wall];
return passOutput;
}
}
//A final check to make sure that the variable is parsed to an integer or decimal
od2 = parseFloat(od2);
id2 = parseFloat(id2);
er = parseInt(er);
ps = parseInt(ps);
wall = parseFloat(wall);
var blength = bLength(mat,od2, id2); //Bushing Length function input/output
//If statement to check if requirements have been met to return the proper information
if(er < qER || ps < 1 || wall > 3){
Logger.log("FAILURE TO FIND SIZE " + passOutput);
return failOutput;}
else{
passOutput = [od2,id2, blength,er, ps, wall];
return passOutput;}
}
//****************************************************************************************
//Sub-function for searching the shell OD inventory, based on the updated OD from toolSearch
function toolSearchOD(od) {
var range = CacheService.getScriptCache().get('rangeSHOD');//Call to data in cache
range = Utilities.parseCsv(range);//All returns from cache need to be parsed from a CSV format to a horizontal array with a permanent row of zero
var size = lastRow("Shell Inventory");//Call to sub-function to determine index of last row of the sheet with data in it.
var found = 0;
od = parseFloat(od);//A built in check to make sure that the variable is parsed to a decimal
var inc = .25;//change to 0 when standardized bushings are implemented
//Remove comments when standardized bushings are implemented
/*if(od>10)
{var inc = .5;}
else
{inc = .25;}*/
while (found != 1){
for(var j=0;j<size;j++)
{
if(range[0][j] == od){
od = range[0][j];
found = 1;
}
}
if(found != 1)
od+=inc;
}
return od;
}
//****************************************************************************************
//Sub-function for searching the shell OD inventory, based on the updated ID from toolSearch
function toolSearchID(id) {
var range = CacheService.getScriptCache().get('rangeSHID');
range = Utilities.parseCsv(range);
var size = lastRow("Shell Inventory");
var found = 0;
id = parseFloat(id);
var inc = .25;//change to 0 when standardized bushings are implemented
//Remove comments when standardized bushings are implemented
/*if(id>10)
{var inc = .5;}
else
{inc = .25;}*/
while (found != 1){
for(var j=0;j<size;j++)
{
if(range[0][j] == id){
id = range[0][j];
found = 1;
}
}
if(found != 1)
id-=inc;
}
return id;
}
//****************************************************************************************
//Sub-function for searching the end ring inventory, based on the updated ID and OD values from toolSearchID and toolSearchOD.
function toolSearchER(od,id) {
var rangeOD = CacheService.getScriptCache().get('rangeEROD');
var rangeID = CacheService.getScriptCache().get('rangeERID');
var rangeQTY = CacheService.getScriptCache().get('rangeERQTY');
rangeOD = Utilities.parseCsv(rangeOD);
rangeID = Utilities.parseCsv(rangeID);
rangeQTY = Utilities.parseCsv(rangeQTY);
var size = lastRow("End Ring Inventory");
var erQTY = 0;
od = parseFloat(od);
id = parseFloat(id);
for(var j=0;j<size;j++)
{
if(rangeID[0][j] == id && rangeOD[0][j] == od){
erQTY += parseInt(rangeQTY[0][j]);
}
}
return erQTY;
}
//****************************************************************************************
//Sub-function for searching the end ring inventory, based on the updated ID and OD values from toolSearchID and toolSearchOD.
function toolSearchPS(od) {
var rangeQTY = CacheService.getScriptCache().get('rangePSQTY');
var rangeOD = CacheService.getScriptCache().get('rangePSOD');
rangeOD = Utilities.parseCsv(rangeOD);
rangeQTY = Utilities.parseCsv(rangeQTY);
var size = lastRow("Pusher Inventory");
var psQTY = 0;
od = parseFloat(od);
od -= .25;
for(var j=0;j<size;j++)
{
if(rangeOD[0][j] == od){
psQTY = rangeQTY[0][j];
}
}
return psQTY;
}
//****************************************************************************************
//Sub-function to calculate bushing wall size based on updated OD and ID inputs from toolSearch, toolSearchOD, and toolSearchID
function wallCall(od,id){
var wall;
wall = (od-id)/2;
return wall;
}
//****************************************************************************************
//Sub-function that puts all required data into a Google cache for more efficent processing. Cache time limit is 1 hour
function cache(){
var ss = SpreadsheetApp.getActive();
var sheetSH = ss.getSheetByName("Shell Inventory");
var sheetSHL = sheetSH.getRange("F2:F").getValues();
var sheetER = ss.getSheetByName("End Ring Inventory");
var sheetPS = ss.getSheetByName("Pusher Inventory");
var rangeSHOD = sheetSH.getRange("D2:D").getValues();
var rangeSHID = sheetSH.getRange("C2:C").getValues();
var rangeERQTY = sheetER.getRange("H2:H").getValues();
var rangeEROD = sheetER.getRange("C2:C").getValues();
var rangeERID = sheetER.getRange("D2:D").getValues();
var rangePSQTY = sheetPS.getRange("G2:G").getValues();
var rangePSOD = sheetPS.getRange("B2:B").getValues();
CacheService.getScriptCache().put('rangeSHOD',rangeSHOD,3600);
CacheService.getScriptCache().put('rangeSHID',rangeSHID,3600);
CacheService.getScriptCache().put('sheetSHL' ,sheetSHL,3600);
CacheService.getScriptCache().put('rangeERID',rangeERID,3600);
CacheService.getScriptCache().put('rangeEROD',rangeEROD,3600);
CacheService.getScriptCache().put('rangeERQTY',rangeERQTY,3600);
CacheService.getScriptCache().put('rangePSQTY',rangePSQTY,3600);
CacheService.getScriptCache().put('rangePSOD',rangePSOD,3600);
}
//****************************************************************************************
//Sub-function to calculate the index of last row of data for a sheet
function lastRow(sheetName){
var ss = SpreadsheetApp.getActive();
var sheet = ss.getSheetByName(sheetName);
var size=sheet.getLastRow();
return size;
}
//****************************************************************************************
//Sub-function to calculate bushing length based on OD and ID shell lengths and type of material
function bLength (mat,od, id){
var rangeID = CacheService.getScriptCache().get('rangeSHID');
var rangeOD = CacheService.getScriptCache().get('rangeSHOD');
var rangeL = CacheService.getScriptCache().get('sheetSHL');
rangeID = Utilities.parseCsv(rangeID);
rangeOD = Utilities.parseCsv(rangeOD);
rangeL = Utilities.parseCsv(rangeL);
var size = lastRow("Shell Inventory");
var lengthID = 0;
var lengthOD = 0;
var blength = 0;
id = parseFloat(id);
od = parseFloat(od);
//Find ID shell length
for(var j=0;j<size;j++)
{
if(rangeID[0][j] == id){
lengthID = rangeL[0][j];
}
}
found = 0;
//Find OD shell length
for(var j=0;j<size;j++)
{
if(rangeOD[0][j] == od){
lengthOD = rangeL[0][j];
}
if(lengthID == 18){
blength = "5 inches *Configuration not recommended*.";}
else if (lengthOD == 18)
blength = "5 inches";
else if(mat == "Hot Mold"){
blength = "6 inches";}
else
blength = "9 inches";
return blength;
}
}
function matType(mat){
var hot = 0;
var matType;
switch (mat){
case 620:
hot = 1;
break;
case 603:
hot = 1;
break;
case 604:
hot = 1;
break;
case 611:
hot = 1;
break;
case 605:
hot = 1;
break;
case 608:
hot = 1;
break;
case 580:
hot = 1;
break;
case 607:
hot = 1;
break;
default:
break;
}
if (hot == 1)
matType = "Hot Mold";
else
matType = "Cold Mold";
return matType;
}
Yes I know it's clunky. The "for" loop requirement is there to keep the script from timing out but it is far from effective and I know there is a better way.
The data is on 3 separate sheets and their is a function that caches all the relevant data to try and limit the amount of calls to the sheet, which helped, but not enough.
How can I make this code more efficient? I need to add more criteria which will require more looping to find the correct set of tooling for a job and I'm afraid this will cause the top level function to exceed the function call time very quickly.
Issue : Upon entering a higher number like 10000, innertext of the new paragraph element is updated only after the for loop ends. Please help to make the innertext get updated for each number.
The increment function is called when an onchange event happens after sending a number as a input to the input element.
JAVASCRIPT :
function increment() {
var count = document.getElementById('ac_count').value; //ac_count is the id of the input element
var stat = document.createElement("p");
stat.id = "current_status";
stat.innerText = "";
document.body.appendChild(stat);
stat.style.display = "block";
for (g = 1; g < count; g++) {
stat.innerText = Number(g + 1) + " out of " + count + " records have been processed";
}
}
The DOM doesn't redraw until the executing thread is free. You need to introduce async delays to your code to see a progressive update.
function increment() {
var count = document.getElementById('ac_count').value;
var stat = document.createElement("p");
stat.id = "current_status";
document.body.appendChild(stat);
var g = 1
var itvl = setInterval(function() {
update(g);
g += Math.floor(Math.random() * 20) + 1
if (g >= count) {
clearInterval(itvl);
update(count);
}
}, 10)
function update(g) {
stat.textContent = g + " out of " + count + " records have been processed";
}
}
<input type=number value=10000 id=ac_count>
<button onclick="increment()">CLICK ME</button>
I'm not suggesting that this is a good solution, but this should achieve the effect you're looking for
function increment() {
var count = document.getElementById('ac_count').value; //ac_count is the id of the input element
var stat = document.createElement("p");
stat.id = "current_status";
stat.innerText = "";
document.body.appendChild(stat);
stat.style.display = "block";
updateInnerText(0, count);
}
function updateInnerText(number, max){
if(number < max){
stat.innerText = Number(number + 1) + " out of " + count + " records have been processed";
setTimeout(function(){
updateInnerText(number+1, max);
}, 500);
}
}
Building a dice game and you get 3 rolls. Once you finish your turn i'm trying to have a "reset" button that will reset the values back to the original spot so the "next person" can play. The values reset as I expected but when I "roll" none of the functions are taking place and i'm pretty new in js so i'm not sure what the problem is.
var playerScore = document.getElementById('firstPlayerScore');
var rollButton = document.getElementById('roll_button');
var dice1 = new dice(1);
var dice2 = new dice(2);
var dice3 = new dice(3);
var dice4 = new dice(4);
var dice5 = new dice(5);
var diceArray = [dice1, dice2, dice3, dice4, dice5];
var cargo = 0;
var numOfRolls = 0;
var cargoButton = document.getElementById('cargo');
var canHaveCargo = false;
function restart(){
dice1 = new dice(1);
dice2 = new dice(2);
dice3 = new dice(3);
dice4 = new dice(4);
dice5 = new dice(5);
diceArray = [dice1, dice2, dice3, dice4, dice5];
cargo = 0;
numOfRolls = 0;
canHaveCargo = false;
addGlow();
updateDiceImageUrl();
document.getElementById("dice1").classList.remove('glowing');
document.getElementById("dice2").classList.remove('glowing');
document.getElementById("dice3").classList.remove('glowing');
document.getElementById("dice4").classList.remove('glowing');
document.getElementById("dice5").classList.remove('glowing');
}
//dice object
function dice(id){
this.id = id;
this.currentRoll = 1;
this.previousRoll = 1;
this.isSelected = false;
this.diceImageUrl = "img/dice/dice1.png";
this.roll = function(){
this.previousRoll = this.currentRoll;
this.currentRoll = getRandomRoll(1, 6);
}
}
//returns an array of all dice that are not currently selected so they can be rolled.
function getRollableDiceList(){
var tempDiceList = [];
for(var i = 0; i < diceArray.length; i++){
if(!diceArray[i].isSelected){
tempDiceList.push(diceArray[i]);
}
}
return tempDiceList;
}
// gets a random number between min and max (including min and max)
function getRandomRoll(min,max){
return Math.floor(Math.random() * (max-min + 1) + min);
}
// calls the roll function on each dice
function rollDice(rollableDiceList){
for(var i = 0; i < rollableDiceList.length; i++){
rollableDiceList[i].roll();
}
}
// updates each dice with the new url for the image that corresponds to what their current roll is
function updateDiceImageUrl(){
for(var i = 0; i < diceArray.length; i++){
var currentDice = diceArray[i];
currentDice.diceImageUrl = "http://boomersplayground.com/img/dice/dice" + currentDice.currentRoll + ".png";
//update div image with img that cooresponds to their current roll
updateDiceDivImage(currentDice);
}
}
//Displays the image that matches the roll on each dice
function updateDiceDivImage(currentDice) {
document.getElementById("dice"+currentDice.id).style.backgroundImage = "url('" + currentDice.diceImageUrl +"')";
}
// returns an array of all
function getNonSelectedDice(){
var tempArray = [];
for(var i = 0; i < diceArray.length; i++){
if(!diceArray[i].isSelected){
tempArray.push(diceArray[i]);
}
tempArray.sort(function(a, b){
return b.currentRoll - a.currentRoll;
});
}
return tempArray;
}
function getSelectedDice(){
var selectedDice = [];
for(var i = 0; i < diceArray.length; i++){
if(diceArray[i].isSelected){
selectedDice.push(diceArray[i]);
}
}
return selectedDice;
}
//boolean variables
var shipExist = false;
var captExist = false;
var crewExist = false;
//checks each dice for ship captain and crew. Auto select the first 6, 5 , 4.
function checkForShipCaptCrew(){
//array of dice that are not marked selected
var nonSelectedDice = getNonSelectedDice();
for(var i = 0; i < nonSelectedDice.length; i++){
//temp variable that represents the current dice in the list
currentDice = nonSelectedDice[i];
if (!shipExist) {
if (currentDice.currentRoll == 6) {
shipExist = true;
currentDice.isSelected = true;
}
}
if (shipExist && !captExist) {
if (currentDice.currentRoll == 5) {
captExist = true;
currentDice.isSelected = true;
}
}
if (shipExist && captExist && !crewExist) {
if (currentDice.currentRoll == 4) {
crewExist = true;
currentDice.isSelected = true;
canHaveCargo = true;
}
}
}
}
function addGlow(){
var selectedDice = getSelectedDice();
for (var i = 0; i < selectedDice.length; i++){
var addGlowDice = selectedDice[i];
var element = document.getElementById('dice' + addGlowDice.id);
element.className = element.className + " glowing";
}
}
function getCargo(){
var cargo = 0;
var moreDice = getNonSelectedDice();
if (canHaveCargo){
for(var i=0; i < moreDice.length; i++){
cargo += moreDice[i].currentRoll;
playerScore.innerHTML = 'You have got ' + cargo + ' in ' + numOfRolls + ' rolls!';
}
} else {
alert("You don't have Ship Captain and the Crew yet!");
}
}
rollButton.addEventListener('click', function(){
//generate rollable dice list
if (numOfRolls < 3) {
var rollableDiceList = getRollableDiceList();
//roll each dice
rollDice(rollableDiceList);
//update dice images
updateDiceImageUrl();
getNonSelectedDice();
// //auto select first 6, 5, 4 (in that order)
checkForShipCaptCrew();
addGlow();
// //adds a red glow to each dice that is selected
numOfRolls++;
}
});
cargoButton.addEventListener('click', getCargo);
var startButton = document.getElementById('restart');
startButton.addEventListener('click', restart);
http://boomer1204.github.io/shipCaptainCrew/
Here is a link to the live game since it's the only way I can describe the problem since I don't know what's not working. If you roll the dice a couple times the dice will get a blue border and be "saved" according to the rules. Now after you hit th restart button that doesn't happen anymore.
Thanks for the help in advance guys
Just add this to your restart()
function restart(){
...
shipExist = false;
capExist = false;
crewExist = false;
...
}
It's hard to replicate without a fiddle, but it seems that you are adding and removing the 'glowing' class using separate processes. Have you tried adding the glowing class the same way you are removing it?
element.classList.add("glowing")
See an example within a fiddle: https://jsfiddle.net/5tstf2f8/
The script itself works fine and all; it is errorless. However, out of running 7,500 times, only 35 were successful. How would I improve the success rate of Regex? Because right now, it is not doing the job.
var IDs = [136758649, 116770724, 136171998]//A lot more IDS than this
var PriceWanting = 60
var scanneditems = 0
var itemerror = 0
document.write('<p id = "title">Total number bought: 0 items for a total of 0</p>')
document.write('<p id = "scanned">Items scanned: 0</p>')
document.write('<p id = "itemerrors">Items scanned: 0</p>')
var buys = 0
var totalrobuxspent = 0
console.log("Bot started")
var loop = setInterval(function()
{
for (var i = 0;i<IDs.length;i++) {
$.get(" http://m.roblox.com/items/" + IDs[i] + "/privatesales",function(data) {
var Regex = /\<span class="currency-robux">([\d,]+)\<\/span\>/;
var PriceSelling = data.match(Regex);
scanneditems = scanneditems + 1
document.getElementById("scanned").innerHTML = "Scanned items: " + scanneditems
PriceSelling = PriceSelling ? PriceSelling[1] : '';
if (PriceSelling.length < 1) {
itemerrors = itemerrors + 1
document.getElementById(''itemserror'').innerHTML = ''Total errors: '' + itemerrors
return
}
PriceSelling = Number(PriceSelling.replace(",",""))
PriceSelling = PriceSelling * 1
totalrobuxspent = totalrobuxspent + PriceSelling
var remaining = PriceWanting - PriceSelling
if (remaining >= -0.1)
{
buys = buys + 1
document.getElementById("title").innerHTML = "Total number of items bought: " + buys + " for a total of " + totalrobuxspent + " "
var Regex2 = /<a href="\/Catalog\/VerifyTransfer\DuserAssetOptionId=([\d,]+)\Damp;expectedPrice=([\d,]+)">/
var HatBuyId = data.match(Regex2)[1]
var HatBuyLink = "http://m.roblox.com/Catalog/VerifyPurchase?assetid=" + HatBuyId + " &type=robux&expectedPrice=" + PriceSelling
var Explorer = document.createElement('iframe');
function Buy(){
Explorer.contentDocument.forms[0].submit();
console.log("Item purchase complete, scanning again.")
var inf = document.createElement('div');
inf.style.fontSize = "18px";
inf.style.background = "rgba(0,0,5,0)";
inf.style.position = "absolute";
inf.style.width = "100%";
inf.style.height = "18pt";
inf.innerText = "Bot currently running. Purchases: "+answer;
document.body.appendChild(inf);
};
Explorer.onload = Buy;
Explorer.width = "100%";
Explorer.height = "85%";
Explorer.src = HatBuyLink;
document.body.innerHTML = "";
document.body.appendChild(Explorer);
}
})
}
},500)
.get is asynchronous. This means that the callback function is not executed until the response is returned. By that point, you are no longer in a loop and in fact the loop has already completed.
Though it's about a slightly different problem, this Question is a very good read to understand how asynchronous calls work.
In addition, continue here would still be illegal, even without the asynchronous behavior, because the function has its own context and is not in the same context as the loop. This simple example would also be illegal and may be easier to understand the context issue:
for(var i=0; i<10; i++){
someFunc();
}
function someFunc(){
continue; // illegal
}
Though in your case the function is an anonymous function, the same concept applies.
Please, use semicolons in your code.
continue;
is applicable in loops, not in functions. Use the
return;
keyword to get out of the context of a function.