In Google Apps Script Color functions I introduced a bunch of functions to manipulate various color spaces from GAS. This was a migration from the same thing in VBA.
I extended this to include additional color spaces such as Hsl, hsv, Lch, Lab amongst others in VBA from which you can generate a selection of color palettes. Here’s the Google Apps Script version. This extensive library of color conversions are available in this shared GAS library. I must admit I found the math a little trickier in the GAS version.
5 color pallete
function getSomePalettes() { // these are the models& properties we are going to process var models = ["lch", "hsl"]; var prop = ["hue", "lightness", "saturation"]; var ncells = 9, swatchSize = 5, rowHeight = 20, columnWidth = 16, spaceHeight = rowHeight / 5, spaceWidth = columnWidth / 5; // get the data, colors and font colors for this sheet var sheetName = "palette"; var cache = mcpher.sheetCache(sheetName).extend((arrayLength(models) + 1) * ncells + 1, (arrayLength(prop) + 1) * swatchSize + 1); var sheet = cache.xParent.getSheetObj(sheetName); var cacheFill = mcpher.sheetCache(sheet, "getBackgroundColors") var cacheColor = mcpher.sheetCache(sheet, "getFontColors"); var r = mcpher.firstcell(cache.xWsRange); //--------create some random colors to test against, and format worksheet for (var n = 1; n <= ncells; n++) { var p = mcpher.makeColorProps( Math.floor((mcpher.VBCOLORS.vbWhite - mcpher.VBCOLORS.vbBlack + 1) * mcpher.Rnd() + mcpher.VBCOLORS.vbBlack)); // reuse existing rather than random ///var p = mcpher.makeColorProps(mcpher.htmlHexToRgb(cache.getValue((n-1)*4+2,1))); var w = mcpher.vResize(mcpher.vOffset(r, (n - 1) * (2 + arrayLength(models)) + 1, 0), arrayLength(models) + 1); cacheColor.setRepeatValue(mcpher.rgbToHTMLHex(p.textColor), w); cacheFill.setRepeatValue(p.htmlHex, w); cache.setRepeatValue(mcpher.Empty(), w); cache.setRowHeight(rowHeight, w); cache.setColumnWidth(columnWidth, w); // name the columns for (var k = 0; k < models.length; k++) cache.setRepeatValue(models[k], mcpher.vResize(mcpher.vOffset(w, k + 1), 1, 1)); // border around mcpher.borderAround(mcpher.vResize(mcpher.vOffset(w, 1), arrayLength(models), 1)); // add a break line with reference color var v = mcpher.vResize(w, 1, arrayLength(prop) * (swatchSize + 1) + 1); cacheFill.setRepeatValue(p.htmlHex, v); cacheColor.setRepeatValue(mcpher.rgbToHTMLHex(p.textColor), v); cache.setRepeatValue(p.htmlHex, mcpher.vResize(v, undefined, 1)); cache.setColumnWidth(columnWidth * 3, v); mcpher.borderAround(v); // add column breaks between props and name them for (var k = 0; k < prop.length; k++) { var v = mcpher.vResize(mcpher.vOffset(w, 0, 1 + (swatchSize + 1) * k), undefined, 1); cache.setColumnWidth(spaceWidth, v); cache.setRepeatValue(prop[k], mcpher.vResize(mcpher.vOffset(v, undefined, 1), 1, 1)); } // add a break line after var v = mcpher.vResize(mcpher.vOffset(w, arrayLength(models) + 1), 1); cache.setRowHeight(spaceHeight, v); cacheFill.setRepeatValue(mcpher.rgbToHTMLHex(mcpher.VBCOLORS.vbWhite), v); cacheColor.setRepeatValue(mcpher.rgbToHTMLHex(mcpher.VBCOLORS.vbBlack), v); cache.setRepeatValue(mcpher.Empty(), v); } // create various palettes for (var k = 0; k < arrayLength(models); k++) { for (var j = 0; j < arrayLength(prop); j++) { for (var n = 1; n <= ncells; n++) { var rowOff = 1 + (n - 1) * (2 + arrayLength(models)); var colOff = 1 + (1 + swatchSize) * (j); var w = mcpher.vOffset(r, rowOff, colOff); var a = makeAPalette(mcpher.htmlHexToRgb(cacheFill.getValue(w.getRow(), w.getColumn())), models[k], prop[j], swatchSize, prop[j] == "lightness"); var v = mcpher.vOffset(w, k+ 1); cacheFill.setRepeatValue(mcpher.VBCOLORS.vbWhite, v); for (var i = 0; i < arrayLength(a); i++) { cacheFill.setRepeatValue(a[i].htmlHex, mcpher.vOffset(v,undefined, i+1)); // the code //cache.setRepeatValue(a[i].htmlHex,mcpher.vOffset(v,undefined, i+1)); } mcpher.borderAround(mcpher.vResize(mcpher.vOffset(v, undefined, 1), undefined, swatchSize)); } } } // write everything out cacheColor.close(); cacheFill.close(); cache.close(); } function arrayLength(a) { return a.length; } function makeAPalette(rgbColor, optModel, optiType, optHowMany, optDescending) { var model = mcpher.fixOptional(optModel, "lch"); var iType = mcpher.fixOptional(optiType, "hue"); var howMany = mcpher.fixOptional(optHowMany, 5); var ph,ps,pl,pf,h,pv,a=[],g; if (model == "lch") { ph = "hStar", ps = "cStar", pl = "LStar", pf = mcpher.lchToRgb; } else { ph = "hue", ps = "saturation", pl = "lightness", pf = mcpher.hslToRgb; } var top = (iType == "hue" ? 360 : 100); g = top / howMany; pv = (iType == "hue" ? ph : (iType == "saturation" ? ps : pl)); var p = mcpher.makeColorProps(rgbColor); h = p[pv]; // do a number of equally spaced props and store in array for (var i =0;i < howMany ;i++ ) { if (h > top) h -= top; // store new value p[pv] =h; // convert back to rgb and redo p = mcpher.makeColorProps(pf(p)); a.push(p); // make a new copy p = mcpher.makeColorProps(p.rgb); h += g; } return mcpher.sortColorProp (a, pv, optDescending); }
For more stuff like this, see from VBA to Google Apps Script