diff --git a/package-lock.json b/package-lock.json index 6e6ea7cf9a9..245089157ce 100644 --- a/package-lock.json +++ b/package-lock.json @@ -19,6 +19,7 @@ "@turf/centroid": "^7.1.0", "base64-arraybuffer": "^1.0.2", "canvas-fit": "^1.5.0", + "color": "^5.0.0", "color-alpha": "1.0.4", "color-normalize": "1.5.0", "color-parse": "2.0.0", @@ -2738,6 +2739,19 @@ "node": ">=0.8" } }, + "node_modules/color": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/color/-/color-5.0.0.tgz", + "integrity": "sha512-16BlyiuyLq3MLxpRWyOTiWsO3ii/eLQLJUQXBSNcxMBBSnyt1ee9YUdaozQp03ifwm5woztEZGDbk9RGVuCsdw==", + "license": "MIT", + "dependencies": { + "color-convert": "^3.0.1", + "color-string": "^2.0.0" + }, + "engines": { + "node": ">=18" + } + }, "node_modules/color-alpha": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/color-alpha/-/color-alpha-1.0.4.tgz", @@ -2835,6 +2849,48 @@ "integrity": "sha512-nKqUYlo0vZATVOFHY810BSYjmCARrG7e5R3UE3CQlyjJTvv5kSSmPG1kzm/oDyyqjehM+lW1RnEt9It9GNa5JA==", "license": "MIT" }, + "node_modules/color-string": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-string/-/color-string-2.0.1.tgz", + "integrity": "sha512-5z9FbYTZPAo8iKsNEqRNv+OlpBbDcoE+SY9GjLfDUHEfcNNV7tS9eSAlFHEaub/r5tBL9LtskAeq1l9SaoZ5tQ==", + "license": "MIT", + "dependencies": { + "color-name": "^2.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/color-string/node_modules/color-name": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-2.0.0.tgz", + "integrity": "sha512-SbtvAMWvASO5TE2QP07jHBMXKafgdZz8Vrsrn96fiL+O92/FN/PLARzUW5sKt013fjAprK2d2iCn2hk2Xb5oow==", + "license": "MIT", + "engines": { + "node": ">=12.20" + } + }, + "node_modules/color/node_modules/color-convert": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-3.1.0.tgz", + "integrity": "sha512-TVoqAq8ZDIpK5lsQY874DDnu65CSsc9vzq0wLpNQ6UMBq81GSZocVazPiBbYGzngzBOIRahpkTzCLVe2at4MfA==", + "license": "MIT", + "dependencies": { + "color-name": "^2.0.0" + }, + "engines": { + "node": ">=14.6" + } + }, + "node_modules/color/node_modules/color-name": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-2.0.0.tgz", + "integrity": "sha512-SbtvAMWvASO5TE2QP07jHBMXKafgdZz8Vrsrn96fiL+O92/FN/PLARzUW5sKt013fjAprK2d2iCn2hk2Xb5oow==", + "license": "MIT", + "engines": { + "node": ">=12.20" + } + }, "node_modules/colors": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/colors/-/colors-1.4.0.tgz", @@ -3166,6 +3222,7 @@ "version": "3.1.0", "resolved": "https://registry.npmjs.org/d3-color/-/d3-color-3.1.0.tgz", "integrity": "sha512-zg/chbXyeBtMQ1LbD/WSoW2DpC3I0mpmPdW+ynRTj/x2DAWYrIY7qeZIHidozwV24m4iavr15lNwIwLxRmOxhA==", + "license": "ISC", "engines": { "node": ">=12" } @@ -10037,12 +10094,10 @@ } }, "node_modules/tinycolor2": { - "version": "1.4.2", - "resolved": "https://registry.npmjs.org/tinycolor2/-/tinycolor2-1.4.2.tgz", - "integrity": "sha512-vJhccZPs965sV/L2sU4oRQVAos0pQXwsvTLkWYdqJ+a8Q5kPFzJTuOFwy7UniPli44NKQGAglksjvOcpo95aZA==", - "engines": { - "node": "*" - } + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/tinycolor2/-/tinycolor2-1.6.0.tgz", + "integrity": "sha512-XPaBkWQJdsf3pLKJV9p4qN/S+fm2Oj8AIPo1BTUhg5oxkvm9+SVEGFdhyOz7tTdUTfvxMiAs4sp6/eZO2Ew+pw==", + "license": "MIT" }, "node_modules/tinyqueue": { "version": "2.0.3", diff --git a/package.json b/package.json index afef26c7980..dffda8af19a 100644 --- a/package.json +++ b/package.json @@ -77,6 +77,7 @@ "@turf/centroid": "^7.1.0", "base64-arraybuffer": "^1.0.2", "canvas-fit": "^1.5.0", + "color": "^5.0.0", "color-alpha": "1.0.4", "color-normalize": "1.5.0", "color-parse": "2.0.0", diff --git a/src/components/color/attributes.js b/src/components/color/attributes.js index 710cc5eb145..7823787f164 100644 --- a/src/components/color/attributes.js +++ b/src/components/color/attributes.js @@ -25,6 +25,6 @@ exports.borderLine = '#BEC8D9'; // with axis.color and Color.interp we aren't using lightLine // itself anymore, instead interpolating between axis.color -// and the background color using tinycolor.mix. lightFraction +// and the background color using Color.mix. lightFraction // gives back exactly lightLine if the other colors are defaults. exports.lightFraction = 100 * (0xe - 0x4) / (0xf - 0x4); diff --git a/src/components/color/index.js b/src/components/color/index.js index 50eccc4a73e..4af743babcc 100644 --- a/src/components/color/index.js +++ b/src/components/color/index.js @@ -1,56 +1,48 @@ 'use strict'; -var tinycolor = require('tinycolor2'); -var isNumeric = require('fast-isnumeric'); -var isTypedArray = require('../../lib/array').isTypedArray; +const isNumeric = require('fast-isnumeric'); +const isTypedArray = require('../../lib/array').isTypedArray; +const color = require('color').default -var color = module.exports = {}; +const { background, defaultLine, defaults, lightLine } = require('./attributes'); -var colorAttrs = require('./attributes'); -color.defaults = colorAttrs.defaults; -var defaultLine = color.defaultLine = colorAttrs.defaultLine; -color.lightLine = colorAttrs.lightLine; -var background = color.background = colorAttrs.background; - -/* - * tinyRGB: turn a tinycolor into an rgb string, but - * unlike the built-in tinycolor.toRgbString this never includes alpha - */ -color.tinyRGB = function(tc) { - var c = tc.toRgb(); - return 'rgb(' + Math.round(c.r) + ', ' + - Math.round(c.g) + ', ' + Math.round(c.b) + ')'; -}; - -color.rgb = function(cstr) { return color.tinyRGB(tinycolor(cstr)); }; +const rgb = cstr => { + const { r, g, b } = color(cstr).rgb().object(); + return `rgb(${Math.round(r)}, ${Math.round(g)}, ${Math.round(b)})`; +} -color.opacity = function(cstr) { return cstr ? tinycolor(cstr).getAlpha() : 0; }; +const opacity = cstr => cstr ? color(cstr).alpha() : 0; -color.addOpacity = function(cstr, op) { - var c = tinycolor(cstr).toRgb(); - return 'rgba(' + Math.round(c.r) + ', ' + - Math.round(c.g) + ', ' + Math.round(c.b) + ', ' + op + ')'; +const addOpacity = (cstr, op) => { + const c = color(cstr).rgb().object(); + return `rgba(${Math.round(c.r)}, ${Math.round(c.g)}, ${Math.round(c.b)}, ${op})`; }; // combine two colors into one apparent color // if back has transparency or is missing, -// color.background is assumed behind it -color.combine = function(front, back) { - var fc = tinycolor(front).toRgb(); - if(fc.a === 1) return tinycolor(front).toRgbString(); - - var bc = tinycolor(back || background).toRgb(); - var bcflat = bc.a === 1 ? bc : { - r: 255 * (1 - bc.a) + bc.r * bc.a, - g: 255 * (1 - bc.a) + bc.g * bc.a, - b: 255 * (1 - bc.a) + bc.b * bc.a +// background is assumed behind it +const combine = (front, back = background) => { + const fc = color(front).rgb().object(); + fc.alpha ||= 1; + if(fc.alpha === 1) return color(front).rgb().string(); + + const bc = color(back).rgb().object(); + bc.alpha ||= 1; + const bcflat = bc.alpha === 1 + ? bc + : { + r: 255 * (1 - bc.alpha) + bc.r * bc.alpha, + g: 255 * (1 - bc.alpha) + bc.g * bc.alpha, + b: 255 * (1 - bc.alpha) + bc.b * bc.alpha + }; + + const fcflat = { + r: bcflat.r * (1 - fc.alpha) + fc.r * fc.alpha, + g: bcflat.g * (1 - fc.alpha) + fc.g * fc.alpha, + b: bcflat.b * (1 - fc.alpha) + fc.b * fc.alpha }; - var fcflat = { - r: bcflat.r * (1 - fc.a) + fc.r * fc.a, - g: bcflat.g * (1 - fc.a) + fc.g * fc.a, - b: bcflat.b * (1 - fc.a) + fc.b * fc.a - }; - return tinycolor(fcflat).toRgbString(); + + return color(fcflat).string(); }; /* @@ -59,17 +51,17 @@ color.combine = function(front, back) { * Ignores alpha channel values. * The resulting color is computed as: factor * first + (1 - factor) * second. */ -color.interpolate = function(first, second, factor) { - var fc = tinycolor(first).toRgb(); - var sc = tinycolor(second).toRgb(); +const interpolate = (first, second, factor) => { + const fc = color(first).rgb().object(); + const sc = color(second).rgb().object(); - var ic = { + const ic = { r: factor * fc.r + (1 - factor) * sc.r, g: factor * fc.g + (1 - factor) * sc.g, b: factor * fc.b + (1 - factor) * sc.b, }; - return tinycolor(ic).toRgbString(); + return color(ic).rgb().string(); }; /* @@ -80,34 +72,28 @@ color.interpolate = function(first, second, factor) { * If lightAmount / darkAmount are used, we adjust by these percentages, * otherwise we go all the way to white or black. */ -color.contrast = function(cstr, lightAmount, darkAmount) { - var tc = tinycolor(cstr); +const contrast = (cstr, lightAmount, darkAmount) => { + let c = color(cstr) - if(tc.getAlpha() !== 1) tc = tinycolor(color.combine(cstr, background)); + if(c.alpha() !== 1) c = color(combine(cstr, background)); - var newColor = tc.isDark() ? - (lightAmount ? tc.lighten(lightAmount) : background) : - (darkAmount ? tc.darken(darkAmount) : defaultLine); + // TODO: Should the API change such that lightAmount/darkAmount are passed in as decimal instead of percent number? + const newColor = color( + c.isDark() + ? (lightAmount ? c.lighten(lightAmount / 100) : background) + : (darkAmount ? c.darken(darkAmount / 100) : defaultLine) + ); - return newColor.toString(); + return newColor.rgb().string(); }; -color.stroke = function(s, c) { - var tc = tinycolor(c); - s.style({stroke: color.tinyRGB(tc), 'stroke-opacity': tc.getAlpha()}); -}; +const stroke = (s, cstr) => s.style({ stroke: rgb(cstr), 'stroke-opacity': opacity(cstr) }); -color.fill = function(s, c) { - var tc = tinycolor(c); - s.style({ - fill: color.tinyRGB(tc), - 'fill-opacity': tc.getAlpha() - }); -}; +const fill = (s, cstr) => s.style({ fill: rgb(cstr), 'fill-opacity': opacity(cstr) }); // search container for colors with the deprecated rgb(fractions) format // and convert them to rgb(0-255 values) -color.clean = function(container) { +const clean = container => { if(!container || typeof container !== 'object') return; var keys = Object.keys(container); @@ -134,13 +120,13 @@ color.clean = function(container) { var el0 = val[0]; if(!Array.isArray(el0) && el0 && typeof el0 === 'object') { - for(j = 0; j < val.length; j++) color.clean(val[j]); + for(j = 0; j < val.length; j++) clean(val[j]); } - } else if(val && typeof val === 'object' && !isTypedArray(val)) color.clean(val); + } else if(val && typeof val === 'object' && !isTypedArray(val)) clean(val); } }; -function cleanOne(val) { +const cleanOne = val => { if(isNumeric(val) || typeof val !== 'string') return val; var valTrim = val.trim(); @@ -181,3 +167,51 @@ function cleanOne(val) { if(rgba) return 'rgba(' + rgbStr + ', ' + parts[3] + ')'; return 'rgb(' + rgbStr + ')'; } + +const equals = (cstr1, cstr2) => cstr1 && cstr2 && color(cstr1).rgb().string() === color(cstr2).rgb().string(); + +const isValid = cstr => { + try { return cstr && !!color(cstr); } + catch { return false; } +} + +const mix = (cstr1, cstr2, weight) => color(cstr1).mix(color(cstr2), weight / 100).rgb().string(); + +const mostReadable = (baseColor, colorList = []) => { + let bestColor; + let bestContrast = -Infinity; + + for (const cstr of colorList) { + const contrast = color(baseColor).contrast(color(cstr)); + if (contrast > bestContrast) { + bestContrast = contrast; + bestColor = color(cstr).rgb().string(); + } + } + + // Fall back to black/white if provided colors don't have proper contrast level + return bestColor && color(baseColor).level(color(bestColor)) + ? bestColor + : mostReadable(baseColor, ["#000", "#fff"]); +}; + +module.exports = { + addOpacity, + background, + clean, + color, + combine, + contrast, + defaultLine, + defaults, + equals, + fill, + interpolate, + isValid, + lightLine, + mix, + mostReadable, + opacity, + rgb, + stroke +} diff --git a/src/components/colorbar/draw.js b/src/components/colorbar/draw.js index 794ff699918..0c2401e1ede 100644 --- a/src/components/colorbar/draw.js +++ b/src/components/colorbar/draw.js @@ -1,7 +1,6 @@ 'use strict'; var d3 = require('@plotly/d3'); -var tinycolor = require('tinycolor2'); var Plots = require('../../plots/plots'); var Registry = require('../../registry'); @@ -548,10 +547,9 @@ function drawColorBar(g, opts, gd) { if(opts._fillgradient) { Drawing.gradient(fillEl, gd, opts._id, isVertical ? 'vertical' : 'horizontalreversed', opts._fillgradient, 'fill'); } else { - // tinycolor can't handle exponents and - // at this scale, removing it makes no difference. + // The color library can't handle exponents and at this scale, removing it makes no difference. var colorString = fillColormap(d).replace('e-', ''); - fillEl.attr('fill', tinycolor(colorString).toHexString()); + fillEl.attr('fill', Color.color(colorString).hex()); } }); @@ -716,8 +714,8 @@ function drawColorBar(g, opts, gd) { if(!isVertical && ( borderwidth || ( - tinycolor(bgcolor).getAlpha() && - !tinycolor.equals(fullLayout.paper_bgcolor, bgcolor) + Color.opacity(bgcolor) && + !Color.equals(fullLayout.paper_bgcolor, bgcolor) ) )) { // for horizontal colorbars when there is a border line or having different background color diff --git a/src/components/colorscale/helpers.js b/src/components/colorscale/helpers.js index bc476e0a9b5..275b134fc35 100644 --- a/src/components/colorscale/helpers.js +++ b/src/components/colorscale/helpers.js @@ -1,7 +1,6 @@ 'use strict'; var d3 = require('@plotly/d3'); -var tinycolor = require('tinycolor2'); var isNumeric = require('fast-isnumeric'); var Lib = require('../../lib'); @@ -167,8 +166,8 @@ function makeColorScaleFunc(specs, opts) { var _range = new Array(N); for(var i = 0; i < N; i++) { - var rgba = tinycolor(range[i]).toRgb(); - _range[i] = [rgba.r, rgba.g, rgba.b, rgba.a]; + const { r, g, b, alpha = 1 } = Color.color(range[i]).rgb().object(); + _range[i] = [r, g, b, alpha]; } var _sclFunc = d3.scale.linear() @@ -189,14 +188,14 @@ function makeColorScaleFunc(specs, opts) { } else if(returnArray) { sclFunc = function(v) { if(isNumeric(v)) return _sclFunc(v); - else if(tinycolor(v).isValid()) return v; - else return Color.defaultLine; + if(Color.isValid(v)) return v; + return Color.defaultLine; }; } else { sclFunc = function(v) { if(isNumeric(v)) return colorArray2rbga(_sclFunc(v)); - else if(tinycolor(v).isValid()) return v; - else return Color.defaultLine; + if(Color.isValid(v)) return v; + return Color.defaultLine; }; } @@ -216,10 +215,10 @@ function colorArray2rbga(colorArray) { r: colorArray[0], g: colorArray[1], b: colorArray[2], - a: colorArray[3] + alpha: colorArray[3] }; - return tinycolor(colorObj).toRgbString(); + return Color.color(colorObj).rgb().string(); } module.exports = { diff --git a/src/components/colorscale/scales.js b/src/components/colorscale/scales.js index 7230f458bc7..c2cef9f44ff 100644 --- a/src/components/colorscale/scales.js +++ b/src/components/colorscale/scales.js @@ -1,6 +1,6 @@ 'use strict'; -var tinycolor = require('tinycolor2'); +const Color = require('../color'); var scales = { Greys: [ @@ -170,7 +170,7 @@ function isValidScaleArray(scl) { for(var i = 0; i < scl.length; i++) { var si = scl[i]; - if(si.length !== 2 || +si[0] < highestVal || !tinycolor(si[1]).isValid()) { + if(si.length !== 2 || +si[0] < highestVal || !Color.isValid(si[1])) { return false; } diff --git a/src/components/drawing/index.js b/src/components/drawing/index.js index 3cb3b447eeb..73be5ab8f9b 100644 --- a/src/components/drawing/index.js +++ b/src/components/drawing/index.js @@ -4,7 +4,6 @@ var d3 = require('@plotly/d3'); var Lib = require('../../lib'); var numberFormat = Lib.numberFormat; var isNumeric = require('fast-isnumeric'); -var tinycolor = require('tinycolor2'); var Registry = require('../../registry'); var Color = require('../color'); @@ -491,11 +490,10 @@ function gradientWithBounds(sel, gd, gradientID, type, colorscale, prop, start, stops.enter().append('stop'); stops.each(function(d) { - var tc = tinycolor(d[1]); d3.select(this).attr({ offset: d[0] + '%', - 'stop-color': Color.tinyRGB(tc), - 'stop-opacity': tc.getAlpha() + 'stop-color': Color.rgb(d[1]), + 'stop-opacity': Color.opacity(d[1]) }); }); }); @@ -549,9 +547,8 @@ drawing.pattern = function(sel, calledBy, gd, patternID, shape, size, solidity, var patternTag; var patternAttrs = {}; - var fgC = tinycolor(fgcolor); - var fgRGB = Color.tinyRGB(fgC); - var fgAlpha = fgC.getAlpha(); + var fgRGB = Color.rgb(fgcolor); + var fgAlpha = Color.opacity(fgcolor); var opacity = fgopacity * fgAlpha; switch(shape) { @@ -704,9 +701,8 @@ drawing.pattern = function(sel, calledBy, gd, patternID, shape, size, solidity, }); if(bgcolor) { - var bgC = tinycolor(bgcolor); - var bgRGB = Color.tinyRGB(bgC); - var bgAlpha = bgC.getAlpha(); + var bgRGB = Color.rgb(bgcolor); + var bgAlpha = Color.opacity(bgcolor); var rects = el.selectAll('rect').data([0]); rects.exit().remove(); diff --git a/src/components/fx/hover.js b/src/components/fx/hover.js index 41ee1352f62..e72c7a31d8c 100644 --- a/src/components/fx/hover.js +++ b/src/components/fx/hover.js @@ -2,7 +2,6 @@ var d3 = require('@plotly/d3'); var isNumeric = require('fast-isnumeric'); -var tinycolor = require('tinycolor2'); var Lib = require('../../lib'); var pushUnique = Lib.pushUnique; @@ -2128,8 +2127,9 @@ function createSpikelines(gd, closestPoints, opts) { hLinePointX = xa._offset + hLinePoint.x; hLinePointY = ya._offset + hLinePoint.y; } - var dfltHLineColor = tinycolor.readability(hLinePoint.color, contrastColor) < 1.5 ? - Color.contrast(contrastColor) : hLinePoint.color; + var dfltHLineColor = Color.color(hLinePoint.color).contrast(Color.color(contrastColor)) < 1.5 + ? Color.contrast(contrastColor) + : hLinePoint.color; var yMode = ya.spikemode; var yThickness = ya.spikethickness; var yColor = ya.spikecolor || dfltHLineColor; @@ -2207,8 +2207,10 @@ function createSpikelines(gd, closestPoints, opts) { vLinePointX = xa._offset + vLinePoint.x; vLinePointY = ya._offset + vLinePoint.y; } - var dfltVLineColor = tinycolor.readability(vLinePoint.color, contrastColor) < 1.5 ? - Color.contrast(contrastColor) : vLinePoint.color; + + var dfltVLineColor = Color.color(vLinePoint.color).contrast(Color.color(contrastColor)) < 1.5 + ? Color.contrast(contrastColor) + : vLinePoint.color; var xMode = xa.spikemode; var xThickness = xa.spikethickness; var xColor = xa.spikecolor || dfltVLineColor; diff --git a/src/lib/coerce.js b/src/lib/coerce.js index 9fa59255bc1..bad6067c23b 100644 --- a/src/lib/coerce.js +++ b/src/lib/coerce.js @@ -1,7 +1,6 @@ 'use strict'; var isNumeric = require('fast-isnumeric'); -var tinycolor = require('tinycolor2'); var extendFlat = require('./extend').extendFlat; @@ -169,7 +168,7 @@ exports.valObjectMeta = { coerceFunction: function(v, propOut, dflt) { if(isTypedArraySpec(v)) v = decodeTypedArraySpec(v); - if(tinycolor(v).isValid()) propOut.set(v); + if(Color.isValid(v)) propOut.set(v); else propOut.set(dflt); } }, @@ -181,11 +180,8 @@ exports.valObjectMeta = { requiredOpts: [], otherOpts: ['dflt'], coerceFunction: function(v, propOut, dflt) { - function isColor(color) { - return tinycolor(color).isValid(); - } if(!Array.isArray(v) || !v.length) propOut.set(dflt); - else if(v.every(isColor)) propOut.set(v); + else if(v.every(color => Color.isValid(color))) propOut.set(v); else propOut.set(dflt); } }, @@ -454,7 +450,7 @@ exports.coerce = function(containerIn, containerOut, attributes, attribute, dflt * Variation on coerce * * Uses coerce to get attribute value if user input is valid, - * returns attribute default if user input it not valid or + * returns attribute default if user input is not valid or * returns false if there is no user input. */ exports.coerce2 = function(containerIn, containerOut, attributes, attribute, dflt) { diff --git a/src/lib/gl_format_color.js b/src/lib/gl_format_color.js index e42170c3d2d..ff4f8c38afc 100644 --- a/src/lib/gl_format_color.js +++ b/src/lib/gl_format_color.js @@ -1,10 +1,10 @@ 'use strict'; var isNumeric = require('fast-isnumeric'); -var tinycolor = require('tinycolor2'); var rgba = require('color-normalize'); var Colorscale = require('../components/colorscale'); +var Color = require('../components/color'); var colorDflt = require('../components/color/attributes').defaultLine; var isArrayOrTypedArray = require('./array').isArrayOrTypedArray; @@ -78,11 +78,10 @@ function parseColorScale(cont) { return colorscale.map(function(elem) { var index = elem[0]; - var color = tinycolor(elem[1]); - var rgb = color.toRgb(); + const { r, g, b, alpha = 1 } = Color.color(elem[1]).rgb().object(); return { index: index, - rgb: [rgb.r, rgb.g, rgb.b, rgb.a] + rgb: [r, g, b, alpha] }; }); } diff --git a/src/plot_api/helpers.js b/src/plot_api/helpers.js index d57be1bc622..c72539e884a 100644 --- a/src/plot_api/helpers.js +++ b/src/plot_api/helpers.js @@ -139,8 +139,7 @@ exports.cleanLayout = function(layout) { */ if(layout.dragmode === 'rotate') layout.dragmode = 'orbit'; - // sanitize rgb(fractions) and rgba(fractions) that old tinycolor - // supported, but new tinycolor does not because they're not valid css + // sanitize rgb(fractions) and rgba(fractions) because they're not valid css Color.clean(layout); // clean the layout container in layout.template @@ -277,8 +276,7 @@ exports.cleanData = function(data) { if(emptyContainer(trace, 'marker')) delete trace.marker; } - // sanitize rgb(fractions) and rgba(fractions) that old tinycolor - // supported, but new tinycolor does not because they're not valid css + // sanitize rgb(fractions) and rgba(fractions) because they're not valid css Color.clean(trace); // remove obsolete autobin(x|y) attributes, but only if true diff --git a/src/plots/cartesian/dragbox.js b/src/plots/cartesian/dragbox.js index f8fa211ad8f..7972b949021 100644 --- a/src/plots/cartesian/dragbox.js +++ b/src/plots/cartesian/dragbox.js @@ -3,7 +3,6 @@ var d3 = require('@plotly/d3'); var Lib = require('../../lib'); var numberFormat = Lib.numberFormat; -var tinycolor = require('tinycolor2'); var supportsPassive = require('has-passive-events'); var Registry = require('../../registry'); @@ -334,9 +333,9 @@ function makeDragBox(gd, plotinfo, x, y, w, h, ns, ew) { y0 = transformedCoords[1]; box = {l: x0, r: x0, w: 0, t: y0, b: y0, h: 0}; - lum = gd._hmpixcount ? - (gd._hmlumcount / gd._hmpixcount) : - tinycolor(gd._fullLayout.plot_bgcolor).getLuminance(); + lum = gd._hmpixcount + ? (gd._hmlumcount / gd._hmpixcount) + : Color.color(gd._fullLayout.plot_bgcolor).luminosity(); path0 = 'M0,0H' + pw + 'V' + ph + 'H0V0'; dimmed = false; zoomMode = 'xy'; diff --git a/src/plots/cartesian/line_grid_defaults.js b/src/plots/cartesian/line_grid_defaults.js index 8808c31f7dd..bc31edc9f74 100644 --- a/src/plots/cartesian/line_grid_defaults.js +++ b/src/plots/cartesian/line_grid_defaults.js @@ -1,6 +1,6 @@ 'use strict'; -var colorMix = require('tinycolor2').mix; +const Color = require('../../components/color'); var colorAttrs = require('../../components/color/attributes'); var Lib = require('../../lib'); @@ -32,7 +32,7 @@ module.exports = function handleLineGridDefaults(containerIn, containerOut, coer delete containerOut.linewidth; } - var gridColorDflt = colorMix(dfltColor, opts.bgColor, opts.blend || colorAttrs.lightFraction).toRgbString(); + var gridColorDflt = Color.mix(dfltColor, opts.bgColor, opts.blend || colorAttrs.lightFraction); var gridColor = coerce2('gridcolor', gridColorDflt); var gridWidth = coerce2('gridwidth'); var gridDash = coerce2('griddash'); @@ -49,7 +49,7 @@ module.exports = function handleLineGridDefaults(containerIn, containerOut, coer } if(opts.hasMinor) { - var minorGridColorDflt = colorMix(containerOut.gridcolor, opts.bgColor, 67).toRgbString(); + var minorGridColorDflt = Color.mix(containerOut.gridcolor, opts.bgColor, 67); var minorGridColor = coerce2('minor.gridcolor', minorGridColorDflt); var minorGridWidth = coerce2('minor.gridwidth', containerOut.gridwidth || 1); var minorGridDash = coerce2('minor.griddash', containerOut.griddash || 'solid'); diff --git a/src/plots/gl3d/layout/axis_defaults.js b/src/plots/gl3d/layout/axis_defaults.js index ae041637a70..2336dc3d8f2 100644 --- a/src/plots/gl3d/layout/axis_defaults.js +++ b/src/plots/gl3d/layout/axis_defaults.js @@ -1,6 +1,6 @@ 'use strict'; -var colorMix = require('tinycolor2').mix; +const Color = require('../../../components/color'); var Lib = require('../../../lib'); var Template = require('../../../plot_api/plot_template'); @@ -58,7 +58,7 @@ module.exports = function supplyLayoutDefaults(layoutIn, layoutOut, options) { }, options.fullLayout); - coerce('gridcolor', colorMix(containerOut.color, options.bgColor, gridLightness).toRgbString()); + coerce('gridcolor', Color.mix(containerOut.color, options.bgColor, gridLightness)); coerce('title.text', axName[0]); // shouldn't this be on-par with 2D? containerOut.setScale = Lib.noop; diff --git a/src/plots/polar/polar.js b/src/plots/polar/polar.js index da7da52c1b6..146c3a40f63 100644 --- a/src/plots/polar/polar.js +++ b/src/plots/polar/polar.js @@ -1,7 +1,6 @@ 'use strict'; var d3 = require('@plotly/d3'); -var tinycolor = require('tinycolor2'); var Registry = require('../../registry'); var Lib = require('../../lib'); @@ -935,7 +934,7 @@ proto.updateHoverAndMainDrag = function(fullLayout) { dimmed = false; var polarLayoutNow = gd._fullLayout[_this.id]; - lum = tinycolor(polarLayoutNow.bgcolor).getLuminance(); + lum = Color.color(polarLayoutNow.bgcolor).luminosity(); zb = dragBox.makeZoombox(zoomlayer, lum, cx, cy, path0); zb.attr('fill-rule', 'evenodd'); diff --git a/src/plots/ternary/ternary.js b/src/plots/ternary/ternary.js index 06a457d6d3e..18ced390ce2 100644 --- a/src/plots/ternary/ternary.js +++ b/src/plots/ternary/ternary.js @@ -1,7 +1,6 @@ 'use strict'; var d3 = require('@plotly/d3'); -var tinycolor = require('tinycolor2'); var Registry = require('../../registry'); var Lib = require('../../lib'); @@ -593,7 +592,7 @@ proto.initInteractions = function() { }; mins = mins0; span0 = _this.aaxis.range[1] - mins0.a; - lum = tinycolor(_this.graphDiv._fullLayout[_this.id].bgcolor).getLuminance(); + lum = Color.color(_this.graphDiv._fullLayout[_this.id].bgcolor).luminosity(); path0 = 'M0,' + _this.h + 'L' + (_this.w / 2) + ', 0L' + _this.w + ',' + _this.h + 'Z'; dimmed = false; diff --git a/src/traces/bar/helpers.js b/src/traces/bar/helpers.js index d1f30a23246..87f0915ff52 100644 --- a/src/traces/bar/helpers.js +++ b/src/traces/bar/helpers.js @@ -1,7 +1,7 @@ 'use strict'; +const Color = require('../../components/color'); var isNumeric = require('fast-isnumeric'); -var tinycolor = require('tinycolor2'); var isArrayOrTypedArray = require('../../lib').isArrayOrTypedArray; exports.coerceString = function(attributeDefinition, value, defaultValue) { @@ -34,7 +34,7 @@ exports.coerceNumber = function(attributeDefinition, value, defaultValue) { }; exports.coerceColor = function(attributeDefinition, value, defaultValue) { - if(tinycolor(value).isValid()) return value; + if(Color.isValid(value)) return value; return (defaultValue !== undefined) ? defaultValue : diff --git a/src/traces/carpet/axis_defaults.js b/src/traces/carpet/axis_defaults.js index 1b45c87f6e5..8147e87d31c 100644 --- a/src/traces/carpet/axis_defaults.js +++ b/src/traces/carpet/axis_defaults.js @@ -135,7 +135,7 @@ module.exports = function handleAxisDefaults(containerIn, containerOut, options) dataAttr: letter }); - var gridColor = coerce2('gridcolor', addOpacity(dfltColor, 0.3)); + var gridColor = coerce('gridcolor', addOpacity(dfltColor, 0.3)); var gridWidth = coerce2('gridwidth'); var gridDash = coerce2('griddash'); var showGrid = coerce('showgrid'); diff --git a/src/traces/heatmap/plot.js b/src/traces/heatmap/plot.js index 2db0d0eb3b2..e7a851da763 100644 --- a/src/traces/heatmap/plot.js +++ b/src/traces/heatmap/plot.js @@ -1,7 +1,6 @@ 'use strict'; var d3 = require('@plotly/d3'); -var tinycolor = require('tinycolor2'); var Registry = require('../../registry'); var Drawing = require('../../components/drawing'); @@ -203,19 +202,19 @@ module.exports = function(gd, plotinfo, cdheatmaps, heatmapLayer) { var xb, xi, v, row, c; function setColor(v, pixsize) { - if(v !== undefined) { - var c = sclFunc(v); - c[0] = Math.round(c[0]); - c[1] = Math.round(c[1]); - c[2] = Math.round(c[2]); - - pixcount += pixsize; - rcount += c[0] * pixsize; - gcount += c[1] * pixsize; - bcount += c[2] * pixsize; - return c; - } - return [0, 0, 0, 0]; + if (v === undefined || pixsize === undefined) return [0, 0, 0, 0]; + + var c = sclFunc(v); + c[0] = Math.round(c[0]); + c[1] = Math.round(c[1]); + c[2] = Math.round(c[2]); + + pixcount += pixsize; + rcount += c[0] * pixsize; + gcount += c[1] * pixsize; + bcount += c[2] * pixsize; + + return c; } function interpColor(r0, r1, xinterp, yinterp) { @@ -341,13 +340,17 @@ module.exports = function(gd, plotinfo, cdheatmaps, heatmapLayer) { } } - rcount = Math.round(rcount / pixcount); - gcount = Math.round(gcount / pixcount); - bcount = Math.round(bcount / pixcount); - var avgColor = tinycolor('rgb(' + rcount + ',' + gcount + ',' + bcount + ')'); + // Guard against dividing by zero and the resulting bad color string + if (pixcount) { + rcount = Math.round(rcount / pixcount); + gcount = Math.round(gcount / pixcount); + bcount = Math.round(bcount / pixcount); - gd._hmpixcount = (gd._hmpixcount||0) + pixcount; - gd._hmlumcount = (gd._hmlumcount||0) + pixcount * avgColor.getLuminance(); + const cstr = `rgb(${rcount}, ${gcount}, ${bcount})`; + + gd._hmpixcount = (gd._hmpixcount || 0) + pixcount; + gd._hmlumcount = (gd._hmlumcount || 0) + pixcount * Color.color(cstr).luminosity(); + } var image3 = plotGroup.selectAll('image') .data(cd); @@ -536,7 +539,7 @@ module.exports = function(gd, plotinfo, cdheatmaps, heatmapLayer) { fontColor = Color.contrast( d.z === undefined ? gd._fullLayout.plot_bgcolor : 'rgba(' + - sclFunc(d.z).join() + + sclFunc(d.z).map(Math.round).join() + ')' ); } diff --git a/src/traces/parcats/parcats.js b/src/traces/parcats/parcats.js index 39f75d3b674..8ce8fa93905 100644 --- a/src/traces/parcats/parcats.js +++ b/src/traces/parcats/parcats.js @@ -3,11 +3,11 @@ var d3 = require('@plotly/d3'); var interpolateNumber = require('d3-interpolate').interpolateNumber; var Plotly = require('../../plot_api/plot_api'); +const Color = require('../../components/color'); var Fx = require('../../components/fx'); var Lib = require('../../lib'); var strTranslate = Lib.strTranslate; var Drawing = require('../../components/drawing'); -var tinycolor = require('tinycolor2'); var svgTextUtils = require('../../lib/svg_text_utils'); function performPlot(parcatsModels, graphDiv, layout, svg) { @@ -426,7 +426,7 @@ function mouseoverPath(d) { var hoverCenterX = d.parcatsViewModel.x + pathCenterX; var hoverCenterY = d.parcatsViewModel.y + pathCenterY; - var textColor = tinycolor.mostReadable(d.model.color, ['black', 'white']); + var textColor = Color.mostReadable(d.model.color); var count = d.model.count; var prob = count / d.parcatsViewModel.model.count; @@ -575,9 +575,7 @@ function stylePathsNoHover(pathSelection) { function stylePathsHover(pathSelection) { pathSelection .attr('fill-opacity', 0.8) - .attr('stroke', function(d) { - return tinycolor.mostReadable(d.model.color, ['black', 'white']); - }) + .attr('stroke', d => Color.mostReadable(d.model.color)) .attr('stroke-width', 0.3); } @@ -936,7 +934,7 @@ function createHoverLabelForColorHovermode(gd, rootBBox, bandElement) { var hovertext = hoverinfoParts.join('
'); // Compute text color - var textColor = tinycolor.mostReadable(bandViewModel.color, ['black', 'white']); + var textColor = Color.mostReadable(bandViewModel.color); return { trace: trace, diff --git a/src/traces/pie/calc.js b/src/traces/pie/calc.js index 1fe5541e7d5..914ab513677 100644 --- a/src/traces/pie/calc.js +++ b/src/traces/pie/calc.js @@ -1,7 +1,6 @@ 'use strict'; var isNumeric = require('fast-isnumeric'); -var tinycolor = require('tinycolor2'); var Color = require('../../components/color'); @@ -89,15 +88,12 @@ function calc(gd, trace) { function makePullColorFn(colorMap) { return function pullColor(color, id) { - if(!color) return false; + if(!color || !Color.isValid(color)) return false; - color = tinycolor(color); - if(!color.isValid()) return false; + const newColor = Color.addOpacity(color, color.getAlpha()); + if(!colorMap[id]) colorMap[id] = newColor; - color = Color.addOpacity(color, color.getAlpha()); - if(!colorMap[id]) colorMap[id] = color; - - return color; + return newColor; }; } @@ -154,11 +150,11 @@ function generateExtendedColors(colorList, extendedColorWays) { colors = colorList.slice(); for(i = 0; i < colorList.length; i++) { - colors.push(tinycolor(colorList[i]).lighten(20).toHexString()); + colors.push(Color.color(colorList[i]).lighten(0.2).hex()); } for(i = 0; i < colorList.length; i++) { - colors.push(tinycolor(colorList[i]).darken(20).toHexString()); + colors.push(Color.color(colorList[i]).darken(0.2).hex()); } extendedColorWays[colorString] = colors; } diff --git a/src/traces/sankey/defaults.js b/src/traces/sankey/defaults.js index d9ca15fea65..8a51fa30577 100644 --- a/src/traces/sankey/defaults.js +++ b/src/traces/sankey/defaults.js @@ -3,7 +3,6 @@ var Lib = require('../../lib'); var attributes = require('./attributes'); var Color = require('../../components/color'); -var tinycolor = require('tinycolor2'); var handleDomainDefaults = require('../../plots/domain').defaults; var handleHoverLabelDefaults = require('../../components/fx/hoverlabel_defaults'); var Template = require('../../plot_api/plot_template'); @@ -63,23 +62,20 @@ module.exports = function supplyDefaults(traceIn, traceOut, defaultColor, layout handleHoverLabelDefaults(linkIn, linkOut, coerceLink, hoverlabelDefault); coerceLink('hovertemplate'); - var darkBG = tinycolor(layout.paper_bgcolor).getLuminance() < 0.333; + var darkBG = Color.color(layout.paper_bgcolor).luminosity() < 0.333; var defaultLinkColor = darkBG ? 'rgba(255, 255, 255, 0.6)' : 'rgba(0, 0, 0, 0.2)'; var linkColor = coerceLink('color', defaultLinkColor); function makeDefaultHoverColor(_linkColor) { - var tc = tinycolor(_linkColor); - if(!tc.isValid()) { - // hopefully the user-specified color is valid, but if not that can be caught elsewhere - return _linkColor; - } - var alpha = tc.getAlpha(); - if(alpha <= 0.8) { - tc.setAlpha(alpha + 0.2); - } else { - tc = darkBG ? tc.brighten() : tc.darken(); - } - return tc.toRgbString(); + // hopefully the user-specified color is valid, but if not that can be caught elsewhere + if(!Color.isValid(_linkColor)) return _linkColor; + + const c = Color.color(_linkColor); + const alpha = c.alpha(); + + return alpha <= 0.8 + ? c.alpha(alpha + 0.2).rgb().string() + : (darkBG ? c.lighten(0.1) : c.darken(0.1)).rgb().string() } coerceLink('hovercolor', Array.isArray(linkColor) ? diff --git a/src/traces/sankey/plot.js b/src/traces/sankey/plot.js index 2ac7ec7206e..8b179c767cb 100644 --- a/src/traces/sankey/plot.js +++ b/src/traces/sankey/plot.js @@ -64,11 +64,11 @@ function nodeNonHoveredStyle(sankeyNode, d, sankey) { function linkHoveredStyle(d, sankey, visitNodes, sankeyLink) { sankeyLink.style('fill', function(l) { if(!l.link.concentrationscale) { - return l.tinyColorHoverHue; + return l.hoverRgb; } }).style('fill-opacity', function(l) { if(!l.link.concentrationscale) { - return l.tinyColorHoverAlpha; + return l.hoverAlpha; } }); @@ -80,11 +80,11 @@ function linkHoveredStyle(d, sankey, visitNodes, sankeyLink) { .filter(function(l) {return l.link.label === label;}) .style('fill', function(l) { if(!l.link.concentrationscale) { - return l.tinyColorHoverHue; + return l.hoverRgb; } }).style('fill-opacity', function(l) { if(!l.link.concentrationscale) { - return l.tinyColorHoverAlpha; + return l.hoverAlpha; } }); } @@ -100,9 +100,9 @@ function linkHoveredStyle(d, sankey, visitNodes, sankeyLink) { function linkNonHoveredStyle(d, sankey, visitNodes, sankeyLink) { sankeyLink.style('fill', function(l) { - return l.tinyColorHue; + return l.rgb; }).style('fill-opacity', function(l) { - return l.tinyColorAlpha; + return l.alpha; }); sankeyLink.each(function(curLink) { @@ -111,8 +111,8 @@ function linkNonHoveredStyle(d, sankey, visitNodes, sankeyLink) { ownTrace(sankey, d) .selectAll('.' + cn.sankeyLink) .filter(function(l) {return l.link.label === label;}) - .style('fill', function(l) {return l.tinyColorHue;}) - .style('fill-opacity', function(l) {return l.tinyColorAlpha;}); + .style('fill', l => l.rgb) + .style('fill-opacity', l => l.alpha); } }); @@ -321,7 +321,7 @@ module.exports = function plot(gd, calcData) { incomingLabel + d.node.targetLinks.length, outgoingLabel + d.node.sourceLinks.length ].filter(renderableValuePresent).join('
'), - color: castHoverOption(obj, 'bgcolor') || d.tinyColorHue, + color: castHoverOption(obj, 'bgcolor') || d.rgb, borderColor: castHoverOption(obj, 'bordercolor'), fontFamily: castHoverOption(obj, 'font.family'), fontSize: castHoverOption(obj, 'font.size'), diff --git a/src/traces/sankey/render.js b/src/traces/sankey/render.js index a07d18a9c9e..74e17425729 100644 --- a/src/traces/sankey/render.js +++ b/src/traces/sankey/render.js @@ -7,7 +7,6 @@ var d3Sankey = require('@plotly/d3-sankey'); var d3SankeyCircular = require('@plotly/d3-sankey-circular'); var c = require('./constants'); -var tinycolor = require('tinycolor2'); var Color = require('../../components/color'); var Drawing = require('../../components/drawing'); var Lib = require('../../lib'); @@ -151,7 +150,7 @@ function sankeyModel(layout, d, traceIndex) { links: flowLinks }; if(link.concentrationscale) { - link.color = tinycolor(link.concentrationscale(link.flow.labelConcentration)); + link.color = link.concentrationscale(link.flow.labelConcentration); } } } @@ -298,8 +297,6 @@ function sankeyModel(layout, d, traceIndex) { } function linkModel(d, l, i) { - var tc = tinycolor(l.color); - var htc = tinycolor(l.hovercolor); var basicKey = l.source.label + '|' + l.target.label; var key = basicKey + '__' + i; @@ -313,10 +310,10 @@ function linkModel(d, l, i) { traceId: d.key, pointNumber: l.pointNumber, link: l, - tinyColorHue: Color.tinyRGB(tc), - tinyColorAlpha: tc.getAlpha(), - tinyColorHoverHue: Color.tinyRGB(htc), - tinyColorHoverAlpha: htc.getAlpha(), + rgb: Color.rgb(l.color), + alpha: Color.opacity(l.color), + hoverRgb: Color.rgb(l.hovercolor), + hoverAlpha: Color.opacity(l.hovercolor), linkPath: linkPath, linkLineColor: d.linkLineColor, linkLineWidth: d.linkLineWidth, @@ -535,7 +532,6 @@ function linkPath() { } function nodeModel(d, n) { - var tc = tinycolor(n.color); var zoneThicknessPad = c.nodePadAcross; var zoneLengthPad = d.nodePad / 2; n.dx = n.x1 - n.x0; @@ -577,9 +573,9 @@ function nodeModel(d, n) { sizeAcross: d.width, forceLayouts: d.forceLayouts, horizontal: d.horizontal, - darkBackground: tc.getBrightness() <= 128, - tinyColorHue: Color.tinyRGB(tc), - tinyColorAlpha: tc.getAlpha(), + darkBackground: Color.color(n.color).isDark(), + rgb: Color.rgb(n.color), + alpha: Color.opacity(n.color), valueFormat: d.valueFormat, valueSuffix: d.valueSuffix, sankey: d.sankey, @@ -937,18 +933,10 @@ module.exports = function(gd, svg, calcData, layout, callbacks) { .call(attachPointerEvents, sankey, callbacks.linkEvents); sankeyLink - .style('stroke', function(d) { - return salientEnough(d) ? Color.tinyRGB(tinycolor(d.linkLineColor)) : d.tinyColorHue; - }) - .style('stroke-opacity', function(d) { - return salientEnough(d) ? Color.opacity(d.linkLineColor) : d.tinyColorAlpha; - }) - .style('fill', function(d) { - return d.tinyColorHue; - }) - .style('fill-opacity', function(d) { - return d.tinyColorAlpha; - }) + .style('stroke', d => salientEnough(d) ? Color.rgb(d.linkLineColor) : d.rgb) + .style('stroke-opacity', d => salientEnough(d) ? Color.opacity(d.linkLineColor) : d.alpha) + .style('fill', d => d.rgb) + .style('fill-opacity', d => d.alpha) .style('stroke-width', function(d) { return salientEnough(d) ? d.linkLineWidth : 1; }) @@ -1022,10 +1010,10 @@ module.exports = function(gd, svg, calcData, layout, callbacks) { nodeRect .style('stroke-width', function(d) {return d.nodeLineWidth;}) - .style('stroke', function(d) {return Color.tinyRGB(tinycolor(d.nodeLineColor));}) + .style('stroke', function(d) {return Color.rgb(d.nodeLineColor);}) .style('stroke-opacity', function(d) {return Color.opacity(d.nodeLineColor);}) - .style('fill', function(d) {return d.tinyColorHue;}) - .style('fill-opacity', function(d) {return d.tinyColorAlpha;}); + .style('fill', d => d.rgb) + .style('fill-opacity', d => d.alpha); nodeRect.transition() .ease(c.ease).duration(c.duration) diff --git a/test/jasmine/tests/axes_test.js b/test/jasmine/tests/axes_test.js index 6314d97a1b0..2e46116330f 100644 --- a/test/jasmine/tests/axes_test.js +++ b/test/jasmine/tests/axes_test.js @@ -7,7 +7,6 @@ var Plots = require('../../../src/plots/plots'); var Lib = require('../../../src/lib'); var Loggers = require('../../../src/lib/loggers'); var Color = require('../../../src/components/color'); -var tinycolor = require('tinycolor2'); var handleTickValueDefaults = require('../../../src/plots/cartesian/tick_value_defaults'); var Cartesian = require('../../../src/plots/cartesian'); @@ -467,11 +466,11 @@ describe('Test axes', function() { yaxis: {} }; supplyLayoutDefaults(layoutIn, layoutOut, fullData); - var lightLine = tinycolor(Color.lightLine).toRgbString(); + var lightLine = Color.color(Color.lightLine).rgb().string(); expect(layoutOut.xaxis.gridwidth).toBe(1); - expect(tinycolor(layoutOut.xaxis.gridcolor).toRgbString()).toBe(lightLine); + expect(Color.color(layoutOut.xaxis.gridcolor).rgb().string()).toBe(lightLine); expect(layoutOut.yaxis.gridwidth).toBe(1); - expect(tinycolor(layoutOut.yaxis.gridcolor).toRgbString()).toBe(lightLine); + expect(Color.color(layoutOut.yaxis.gridcolor).rgb().string()).toBe(lightLine); }); it('should set gridcolor/gridwidth to undefined if showgrid is false', function() { @@ -566,11 +565,9 @@ describe('Test axes', function() { var frac = 100 * (0xe - 0x4) / (0xf - 0x4); supplyLayoutDefaults(layoutIn, layoutOut, fullData); - expect(layoutOut.xaxis.gridcolor) - .toEqual(tinycolor.mix('red', bgColor, frac).toRgbString()); + expect(layoutOut.xaxis.gridcolor).toEqual(Color.mix('red', bgColor, frac)); expect(layoutOut.yaxis.gridcolor).toEqual('blue'); - expect(layoutOut.yaxis2.gridcolor) - .toEqual(tinycolor.mix('#444', bgColor, frac).toRgbString()); + expect(layoutOut.yaxis2.gridcolor).toEqual(Color.mix('#444', bgColor, frac)); }); it('should default to a dark color for tickfont when plotting background is light', function() { @@ -583,7 +580,7 @@ describe('Test axes', function() { }; supplyLayoutDefaults(layoutIn, layoutOut, fullData); - expect(layoutOut.xaxis.tickfont.color).toEqual('#444'); + expect(layoutOut.xaxis.tickfont.color).toEqual('rgb(68, 68, 68)'); }); it('should default to a light color for tickfont when plotting background is dark', function() { @@ -596,7 +593,7 @@ describe('Test axes', function() { }; supplyLayoutDefaults(layoutIn, layoutOut, fullData); - expect(layoutOut.xaxis.tickfont.color).toEqual('#fff'); + expect(layoutOut.xaxis.tickfont.color).toEqual('rgb(255, 255, 255)'); }); it('should not coerce ticklabelposition on *multicategory* axes for now', function() { diff --git a/test/jasmine/tests/color_test.js b/test/jasmine/tests/color_test.js index 990092529b7..a3f617d737f 100644 --- a/test/jasmine/tests/color_test.js +++ b/test/jasmine/tests/color_test.js @@ -155,7 +155,7 @@ describe('Test color:', function() { } }; - Color.fill(mockElement, 'rgba(255,255,0,0.5'); + Color.fill(mockElement, 'rgba(255,255,0,0.5)'); }); }); @@ -168,7 +168,7 @@ describe('Test color:', function() { } }; - Color.stroke(mockElement, 'rgba(255,255,0,0.5'); + Color.stroke(mockElement, 'rgba(255,255,0,0.5)'); }); }); @@ -176,19 +176,19 @@ describe('Test color:', function() { it('should darken light colors', function() { var out = Color.contrast('#eee', 10, 20); - expect(out).toEqual('#bbbbbb'); + expect(out).toEqual('rgb(190, 190, 190)'); }); it('should darken light colors (2)', function() { var out = Color.contrast('#fdae61', 10, 20); - expect(out).toEqual('#f57a03'); + expect(out).toEqual('rgb(252, 139, 28)'); }); it('should lighten dark colors', function() { var out = Color.contrast('#2b83ba', 10, 20); - expect(out).toEqual('#449dd4'); + expect(out).toEqual('rgb(47, 144, 205)'); }); }); }); diff --git a/test/jasmine/tests/gl3dlayout_test.js b/test/jasmine/tests/gl3dlayout_test.js index ceb049d24f3..75d271f7b6c 100644 --- a/test/jasmine/tests/gl3dlayout_test.js +++ b/test/jasmine/tests/gl3dlayout_test.js @@ -1,7 +1,6 @@ var Plotly = require('../../../lib/index'); var Gl3d = require('../../../src/plots/gl3d'); -var tinycolor = require('tinycolor2'); var Color = require('../../../src/components/color'); var createGraphDiv = require('../assets/create_graph_div'); @@ -378,10 +377,10 @@ describe('Test Gl3d layout defaults', function() { supplyLayoutDefaults(layoutIn, layoutOut, fullData); expect(layoutOut.scene.xaxis.gridcolor) - .toEqual(tinycolor.mix('red', bgColor, frac).toRgbString()); + .toEqual(Color.mix('red', bgColor, frac)); expect(layoutOut.scene.yaxis.gridcolor).toEqual('blue'); expect(layoutOut.scene.zaxis.gridcolor) - .toEqual(tinycolor.mix('#444', bgColor, frac).toRgbString()); + .toEqual(Color.mix('#444', bgColor, frac)); }); it('should disable converting numeric strings using axis.autotypenumbers', function() { diff --git a/test/jasmine/tests/hover_label_test.js b/test/jasmine/tests/hover_label_test.js index ba3211c458a..7e716fc4f78 100644 --- a/test/jasmine/tests/hover_label_test.js +++ b/test/jasmine/tests/hover_label_test.js @@ -949,10 +949,10 @@ describe('hover info', function() { fontColor: 'rgb(255, 255, 255)' }, { bgcolor: 'rgb(0, 200, 0)', - bordercolor: 'rgb(255, 255, 255)', + bordercolor: 'rgb(68, 68, 68)', fontSize: 13, fontFamily: 'Arial', - fontColor: 'rgb(255, 255, 255)' + fontColor: 'rgb(68, 68, 68)' }, { bgcolor: 'rgb(255, 127, 14)', bordercolor: 'rgb(68, 68, 68)',