These articles are abridged from my book on Office to Apps migration. Going GAS, from VBA to Google Apps Script. Now available for directly from O’Reilly or Amazon.
Many applications have their own names for colors in their palettes. This example features an Apps Script library to retrieve and manipulate colors according to their names in their home palettes. The known palettes currently are Material colors, HTML named colors and the Google Apps Palette. The Google Apps Palette looks like this in the GUI.![](https://ramblings.mcpher.com/wp-content/uploads/2019/05/colorsch1.png)
![](https://ramblings.mcpher.com/wp-content/uploads/2019/05/colorsch2.png)
style=”border:1px solid #000000;”
![](https://ramblings.mcpher.com/wp-content/uploads/2019/05/colorsch3.png)
![](https://ramblings.mcpher.com/wp-content/uploads/2019/05/colorsch4.png)
MBo5MKxo06_g-0n5MOckL0ai_d-phDA33
It’s also available on Github if you prefer, and the test spreadsheet is here if you’d like to make a copy.
Some examples (if you are using the library you’ll need to prefix ColorList with the library identifier eg cColorList.ColorList.getColor()) function test() { // get a color properties Logger.log(JSON.stringify(cColorList.ColorList.getColor(‘google’,’light red berry 1′))); // get a color properties by hex code Logger.log(JSON.stringify(cColorList.ColorList.getColorName(‘google’,’#f3f3f3′))); // get a color properties by rgb number Logger.log(JSON.stringify(cColorList.ColorList.getColorName(‘html’,255))); // get closest Logger.log(JSON.stringify(cColorList.ColorList.getClosest (‘html’ , ‘#ff9900’))); Logger.log(JSON.stringify(cColorList.ColorList.getClosest (‘material’ , ‘#ff9900’))); // check grey/gray Logger.log(JSON.stringify(cColorList.ColorList.getColor(‘material’,’grey 600′))); Logger.log(JSON.stringify(cColorList.ColorList.getColor(‘google’,’light gray 2′))); // get closest var lister = cColorList.ColorList; Logger.log(JSON.stringify(lister.getClosest (‘material’ , lister.getColor(‘google’,’red berry’).value))); } The result is not only the code matching the name and palette, but loads of additional color related information (see Color Arranger for more information on these properties).{
"name": "light red berry 1",
"value": "#ca4126",
"palette": "google",
"status": "ok",
"properties": {
"rgb": 2507210,
"red": 202,
"green": 65,
"blue": 38,
"htmlHex": "#ca4126",
"luminance": 0.16378548548538505,
"textColor": "#ffffff",
"contrastRatio": 4.91146532991259,
"black": 0.207843137254902,
"yellow": 0.8118811881188118,
"magenta": 0.6782178217821783,
"cyan": 0,
"hue": 9.878048780487813,
"saturation": 68.33333333333333,
"lightness": 47.05882352941176,
"value": 0.792156862745098,
"x": 26.597269352335072,
"y": 16.47709067915203,
"z": 3.612286684447369,
"LStar": 47.594296368851595,
"aStar": 52.928166803487386,
"bStar": 45.38090169447055,
"cStar": 69.71956023800627,
"hStar": 40.609968669570854
}
}
You can then use this in your Apps Script code to set background colors and avoid worrying about hex codes. (spacing and case are ignored in the color names) – for example.
ColorList.getColor('google','cornflower blue').value
Text Color
A very useful property is the the textColor, which will be set to either black or white, depending on which is the best font color to use with the given background color. This property can be used to set the font color appropriately if you change the background color of a cell.ColorList.getColor('google','light red berry 1').properties.textColor
Matching Colors
This library also provides a useful way to get the closest match in a palette for some desired color.
This snip shows the beginning of the result of finding the nearest match between the html palette and the google palette.![](https://ramblings.mcpher.com/wp-content/uploads/2019/05/colorsch5.png)
![](https://ramblings.mcpher.com/wp-content/uploads/2019/05/colorsch6.png)
![](https://ramblings.mcpher.com/wp-content/uploads/2019/05/colorsch7.png)
The Code for matching colors.
Finding the nearest match for a given color code in a palette is simple. Here’s we’re looking for the closest color in the html palette to #ff9900 (orange in the google palette).Logger.log(JSON.stringify(ColorList.getClosest ('html' , '#ff9900')));
The query could also be written like this.
Logger.log(JSON.stringify(ColorList.getClosest ('html' , ColorList.getColor('google' , 'orange' ))));
It gives a result like this, where diff is a value between 0-100. The lower, the better the match.
{
"diff": 4.2351903633318795,
"member": {
"name": "Orange",
"value": "#ffa500"
}
}
Code for comparing to complete color schemes and dumping the result
// get the best match between html and google and material palettes function match () { var ss = SpreadsheetApp.getActiveSpreadsheet(); var lister = cColorList.ColorList; // compare combinations of palettes comparePalettes_ (‘google’,’html’); comparePalettes_ (‘google’,’material’); comparePalettes_ (‘html’,’google’); comparePalettes_ (‘html’,’material’); comparePalettes_ (‘material’,’html’); comparePalettes_ (‘material’,’google’); /** * @param {string} p1 palette1 * @param {string} p2 palette2 */ function comparePalettes_ (p1, p2) { // do comparison and write to sheet var sheet = ss.getSheetByName(p1+’_’+ p2) || ss.insertSheet(p1+’_’+ p2); // clear the sheet sheet.clearContents(); // get each of the palettes var list1 = lister.getList(p1); // add the properties to the sheet var heads = {}; heads[p1+’Name’] = Object.keys(heads).length; heads[p1+’Value’] = Object.keys(heads).length; heads[p2+’Name’] = Object.keys(heads).length; heads[p2+’Value’] = Object.keys(heads).length; heads.difference = Object.keys(heads).length; // find the nearest matches var values = Object.keys(list1).map(function(d) { // get the nearest match in the other list var best = lister.getClosest (p2 , list1[d].value); // make this row var row = []; row[heads[p1+’Name’]] = list1[d].name; row[heads[p1+’Value’]] = list1[d].value; row[heads[p2+’Name’]] = best.member.name; row[heads[p2+’Value’]] = best.member.value; row[heads.difference] = best.diff; return row; }); // now write the whole thing out sheet.getRange (1,1,values.length+1 , Object.keys(heads).length) .setValues([Object.keys(heads)].concat(values)); // colorize the columns sheet.getRange (2,1+heads[p1+’Name’],values.length , 2) .setBackgrounds(values.map (function(row) { return row.slice(0,2).map(function(col) { return row[heads[p1+’Value’]]; }); })); sheet.getRange (2,1+heads[p2+’Name’],values.length , 2) .setBackgrounds(values.map (function(row) { return row.slice(0,2).map(function(col) { return row[heads[p2+’Value’]]; }); })); // choose best font color sheet.getRange (2,1+heads[p1+’Name’],values.length , 2) .setFontColors(values.map (function(row) { return row.slice(0,2).map(function(col) { return lister.getColor(p2,row[heads[p2+’Name’]]).properties.textColor; }); })); sheet.getRange (2,1+heads[p2+’Name’],values.length , 2) .setFontColors(values.map (function(row) { return row.slice(0,2).map(function(col) { return lister.getColor(p2,row[heads[p2+’Name’]]).properties.textColor; }); })); } }
Adding palettes
It is possible to add your own palettes with a simple pattern. To demonstrate, I’ll use the material color design principle as demonstrated in the material palette site, where you can create something like this given a primary and an accent color.![](https://ramblings.mcpher.com/wp-content/uploads/2019/05/colorsch8.png)
![](https://ramblings.mcpher.com/wp-content/uploads/2019/05/colorsch9.png)
var theCombination = new cColorList.MaterialPalette('pink','blue');
and components accessed like this, which allows complete abstraction from the color scheme used.
var accent = lister.getColor (theCombination.getName(), 'accent').value;
Here’s the code for creating a selection of combinations, each on its own sheet.
// generate various material palette combinations
function generateMaterial() {
var lister = cColorList.ColorList;
var ss = SpreadsheetApp.getActiveSpreadsheet();
// here's a list of palette combinations to try
[['pink','lime'],['amber','blue'],['purple','deeporange'],['deeporange','purple']].forEach(function (combination) {
// create the material palette
var mp = new cColorList.MaterialPalette(combination[0],combination[1]);
// a sheet for each known combination or create one
var sheet = ss.getSheetByName(mp.getName()) || ss.insertSheet(mp.getName());
// clear the sheet
sheet.clear();
//now we can use that with the normal lister stuff show all the props on a sheet
var members = lister.getList(mp.getName());
sheet.getRange(1,1,1,1).setValues ([['combination:' + mp.getName()]]);
Object.keys(members).forEach(function(d,i) {
// get the details on the material palette
var color = lister.getColorName ('material', members[d].value);
// write the details
sheet.getRange(i+2,1,1,3).setValues ([[members[d].name,color.name,members[d].value]]);
// set the background to show the color
sheet.getRange(i+2,1,1,3).setBackgrounds ([[members[d].value,members[d].value,members[d].value]]);
// use a contrasting text color if it exists in the material list, otherwise use the material text color
var textColor = color.properties ? color.properties.textColor : members.primaryText;
sheet.getRange(i+2,1,1,3).setFontColors ([[textColor,textColor,textColor]]);
// specific colors can now be called out abstractly like this - allowing easy refactoring.
Logger.log( lister.getColor(mp.getName() , 'primary').value);
Logger.log( lister.getColor(mp.getName() , 'dark').value);
Logger.log( lister.getColor(mp.getName() , 'light').value);
Logger.log( lister.getColor(mp.getName() , 'accent').value);
Logger.log( lister.getColor(mp.getName() , 'primaryText').value);
Logger.log( lister.getColor(mp.getName() , 'secondaryText').value);
});
});
}
Creating your own.
The material combination code is in the ColorList library but it’s straightforward to create your own by adapting this pattern. In this case, the colors are picked up from the material palette, but they can be anything you want them to be, as can the properties like dark, light and so on.'use strict';
var MaterialPalette = function (primary, accent) {
var self = this;
var primary_ = (primary || 'Indigo').toLowerCase();
var accent_ = (accent || 'Amber').toLowerCase();
self.getName = function () {
return 'material' + primary_ + accent_;
};
var gc = ColorList.getColor;
// add to known palettes
KnownPalettes.palettes[self.getName()] = {
"dark":gc('material ' , primary_ + " 700").value,
"light":gc('material ' ,primary_ + " 100").value,
"primary":gc('material ' ,primary_ + " 500").value,
"icons":gc('material ' ,"white").value,
"accent":gc('material ' ,accent_ + (["pink","blue"].indexOf(accent_) === -1 ? " 500" : "a200")).value,
"primaryText":gc('material ' ,"gray 900").value,
"secondaryText":"#727272",
"divider":"#B6B6B6"
};
// update the keys.
ColorList.reset();
}
Dumping the color properties.
Here’s an snip of dumping all the color properties for each of these palettes to a Sheet.
The google palette.
The html palette
The material palette
The code for dumping the palettes
// show all palettes, 1 sheet per palette
function showPalettes() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var lister = cColorList.ColorList;
lister.getPalettes().forEach(function(pal) {
// a sheet for each known palette or create one
var sheet = ss.getSheetByName(pal) || ss.insertSheet(pal);
// clear the sheet
sheet.clearContents();
// get the colors in each palette
var palette = lister.getList(pal);
// add the properties to the sheet
var heads,values = Object.keys(palette).map (function (color) {
var data = lister.getColor(pal, color);
if (!heads) {
heads = {};
heads.name = 0, heads.value = 1;
// and the color properties
Object.keys(data.properties).reduce(function(p,c) {
p = Object.keys(p).length;
return p;
},heads);
}
// add the data
return Object.keys(data.properties).reduce(function(p,c) {
p[heads] = data.properties;
return p;
},[data.name,data.value]);
});
// now write the whole thing out
sheet.getRange (1,1,values.length+1 , Object.keys(heads).length)
.setValues([Object.keys(heads)].concat(values));
// now to color the lines
sheet.getRange (2,1,values.length , Object.keys(heads).length)
.setBackgrounds(values.map (function(row) {
return row.map(function(col) {
return row[heads.htmlHex];
});
}));
// choose best font color
sheet.getRange (2,1,values.length , Object.keys(heads).length)
.setFontColors(values.map (function(row) {
return row.map(function(col) {
return row[heads.textColor];
});
}))
});
}
Code to generate the palettes with comparison notes.
![](https://ramblings.mcpher.com/wp-content/uploads/2019/05/colorsch13.png)
MBo5MKxo06_g-0n5MOckL0ai_d-phDA33
It’s also available on Github if you prefer, and the test spreadsheet is here if you’d like to make a copy.
Material color list adapted from https://github.com/danlevan/google-material-color
For more like this, see Color Arranger.