Skip to content
Draft
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
c17371a
Switch color library
camdecoster Aug 15, 2025
d6d1e9e
Add utility functions
camdecoster Aug 19, 2025
b15bdca
Switch references to new color library
camdecoster Aug 21, 2025
a1e2dee
Fix bad method calls; fix NaN bugs
camdecoster Aug 21, 2025
4b97ca9
Update tests per library change
camdecoster Aug 21, 2025
17fe004
Use correct method name
camdecoster Aug 22, 2025
e314022
Use alternate coerce function to avoid gridcolor of `false`
camdecoster Aug 22, 2025
0ab7cd1
Merge remote-tracking branch 'origin/master' into cam/7523/switch-col…
camdecoster Aug 26, 2025
7552832
Update function call
camdecoster Aug 26, 2025
5d0322a
Update tests per library change
camdecoster Aug 26, 2025
5964bee
Update attribute, description to remove hsv
camdecoster Aug 29, 2025
d6853e4
Convert hsv value to rgb in test mock
camdecoster Aug 29, 2025
93a8365
Override color-string package dependency
camdecoster Nov 17, 2025
fe7b607
Merge remote-tracking branch 'origin/master' into cam/7523/switch-col…
camdecoster Nov 17, 2025
5c2dbda
Remove tinycolor2 library
camdecoster Nov 17, 2025
2d5d3e0
Linting/formatting
camdecoster Nov 17, 2025
5e329a6
Update test
camdecoster Nov 17, 2025
8a3f5f4
Use minified plotly.js for making baselines
camdecoster Nov 18, 2025
b43ff75
Add logging
camdecoster Nov 19, 2025
f27aa55
Merge remote-tracking branch 'origin/master' into cam/7523/switch-col…
camdecoster Apr 21, 2026
d6127d1
Refactor to better match tinycolor2
camdecoster Apr 24, 2026
fc905c7
Update schema
camdecoster Apr 24, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Switch references to new color library
  • Loading branch information
camdecoster committed Aug 21, 2025
commit b15bdca973257f2216b89eadd2925b94e222b5c2
2 changes: 1 addition & 1 deletion src/components/color/attributes.js
Original file line number Diff line number Diff line change
Expand Up @@ -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);
24 changes: 23 additions & 1 deletion src/components/color/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -170,10 +170,30 @@ const cleanOne = val => {
const equals = (cstr1, cstr2) => cstr1 && cstr2 && color(cstr1).rgb().string() === color(cstr2).rgb().string();

const isValid = cstr => {
try { return !!color(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,
Expand All @@ -188,6 +208,8 @@ module.exports = {
interpolate,
isValid,
lightLine,
mix,
mostReadable,
opacity,
rgb,
stroke
Expand Down
10 changes: 4 additions & 6 deletions src/components/colorbar/draw.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
'use strict';

var d3 = require('@plotly/d3');
var tinycolor = require('tinycolor2');

var Plots = require('../../plots/plots');
var Registry = require('../../registry');
Expand Down Expand Up @@ -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());
}
});

Expand Down Expand Up @@ -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
Expand Down
17 changes: 8 additions & 9 deletions src/components/colorscale/helpers.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
'use strict';

var d3 = require('@plotly/d3');
var tinycolor = require('tinycolor2');
var isNumeric = require('fast-isnumeric');

var Lib = require('../../lib');
Expand Down Expand Up @@ -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()
Expand All @@ -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;
};
}

Expand All @@ -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 = {
Expand Down
4 changes: 2 additions & 2 deletions src/components/colorscale/scales.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
'use strict';

var tinycolor = require('tinycolor2');
const Color = require('../color');

var scales = {
Greys: [
Expand Down Expand Up @@ -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;
}

Expand Down
16 changes: 6 additions & 10 deletions src/components/drawing/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -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');
Expand Down Expand Up @@ -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])
});
});
});
Expand Down Expand Up @@ -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) {
Expand Down Expand Up @@ -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();
Expand Down
11 changes: 6 additions & 5 deletions src/components/fx/hover.js
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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(contrastColor) < 1.5
? Color.contrast(contrastColor)
: hLinePoint.color;
var yMode = ya.spikemode;
var yThickness = ya.spikethickness;
var yColor = ya.spikecolor || dfltHLineColor;
Expand Down Expand Up @@ -2207,8 +2207,9 @@ 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(contrastColor) < 1.5
? Color.contrast(contrastColor)
: vLinePoint.color;
var xMode = xa.spikemode;
var xThickness = xa.spikethickness;
var xColor = xa.spikecolor || dfltVLineColor;
Expand Down
8 changes: 2 additions & 6 deletions src/lib/coerce.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
'use strict';

var isNumeric = require('fast-isnumeric');
var tinycolor = require('tinycolor2');

var extendFlat = require('./extend').extendFlat;

Expand Down Expand Up @@ -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);
}
},
Expand All @@ -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);
}
},
Expand Down
6 changes: 2 additions & 4 deletions src/lib/gl_format_color.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
'use strict';

var isNumeric = require('fast-isnumeric');
var tinycolor = require('tinycolor2');
var rgba = require('color-normalize');

var Colorscale = require('../components/colorscale');
Expand Down Expand Up @@ -78,11 +77,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]
};
});
}
Expand Down
6 changes: 2 additions & 4 deletions src/plot_api/helpers.js
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down
7 changes: 3 additions & 4 deletions src/plots/cartesian/dragbox.js
Original file line number Diff line number Diff line change
Expand Up @@ -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');
Expand Down Expand Up @@ -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';
Expand Down
6 changes: 3 additions & 3 deletions src/plots/cartesian/line_grid_defaults.js
Original file line number Diff line number Diff line change
@@ -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');

Expand Down Expand Up @@ -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');
Expand All @@ -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');
Expand Down
4 changes: 2 additions & 2 deletions src/plots/gl3d/layout/axis_defaults.js
Original file line number Diff line number Diff line change
@@ -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');
Expand Down Expand Up @@ -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;
Expand Down
3 changes: 1 addition & 2 deletions src/plots/polar/polar.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
'use strict';

var d3 = require('@plotly/d3');
var tinycolor = require('tinycolor2');

var Registry = require('../../registry');
var Lib = require('../../lib');
Expand Down Expand Up @@ -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');
Expand Down
3 changes: 1 addition & 2 deletions src/plots/ternary/ternary.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
'use strict';

var d3 = require('@plotly/d3');
var tinycolor = require('tinycolor2');

var Registry = require('../../registry');
var Lib = require('../../lib');
Expand Down Expand Up @@ -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;

Expand Down
Loading
Loading