get color of element in D3 - javascript

For the following d3 codes:
var previousElement = d3.select(this);
console.log(previousElement.attr("style"));
The result is like:
fill: red;
or
fill: rgb(152, 223, 138);
Then how can I get the exact color of this element, so that I may doing a judge like:
if ( elementColor == 'red')
or
if (elementColor == 'rgb(152, 223, 138)')
I tried var elementColor = previousElement.attr("style").fill, it returns null.

I believe what you want is previousElement.style('fill') instead of using .attr('style'). See https://github.com/mbostock/d3/wiki/Selections#style for documentation.
You may also want to look at the D3 Colors documentation, https://github.com/mbostock/d3/wiki/Colors, as that may help you even more.

You can use d3.rgb() to parse whatever is specified as the style and then compare the R, G, and B components:
var colour = d3.rgb(previousElement.attr("style"));
if(colour.r == 255 && colour.g == 0 && colour.b == 0) {
// ...
}

Related

Is there a way to automatically change the shade of background color?

Was wondering if there was a way to use a spectrum to change the background color based off of variables such as temp the higher it is, the more the colour will become orange from blue? or would I actually have to assign values
if (temp < 10) {
document.body.className = "background-cold";
} else if (temp > 10) {
document.body.className = "background-warm";
}
.background-cold {
background: linear-gradient(
179.31deg,
rgba(48, 87, 89, 0.97) 9.28%,
#fdfeff 167.45%
);
}
.background-warm {
background: linear-gradient(
179.31deg,
rgba(204, 101, 26, 0.97) 9.28%,
#fdfeff 167.45%
);
}
var hue = temp * someScale; // use some formula to determine the appropriate hue from the temperature
var saturation = 1;
var lightness = 1;
document.body.style.backgroundImage = `linear-gradient(179.31deg, hsla(${hue}%,${saturation}%,${lightness}%) 9.28%, #fdfeff 167.45%)`;
For the approach you intend to do I don't recomemend using the .className attribution. It will be hardcoded and that's not what you want. You can just use style.setProperty(string, string) in wich the first parameter is the CSS atttribute and the second parameter is the CSS value. Both of them need to be strings in order to work.
let colorValue = 'linear-gradient(VALUES)';
document.body.style.setProperty('background', colorValue);
By using the previous code you can now set directly the background you want. However your still need a function to create a dynamic colorValue according to the temperature. This can become a little complex depending on the color values you intend to apply. A possible solution for this can be found in the following answer: https://stackoverflow.com/a/12934900/11860800.

Amcharts4: 'legendSettings' 'itemValueText' to check for empty or undefined value

So, I have created a percentage column chart where on bar hover, I am showing the data in tooltip and in legend similar to https://www.amcharts.com/docs/v4/concepts/legend/#Interacting_with_cursor.
Also I have added % in the end. (I am getting data like 40, 55, 90 which means 40%, 50% and 90% respectively from backend API not like 0.4 or 0.5).
I am displaying the average percentage in the starting also.
series.legendSettings.itemValueText = "[bold]{valueY}%[/]";
series.legendSettings.valueText = "(Avg: [bold]{valueY.average.formatNumber('#.##')}%[/])";
So in some case for whole data-set one of the column is null or undefined, I am not getting the key itself and this leads to legend display only % . On hover it will display %.
So my question is - Is there some way where we can check 'itemValueText' or {valueY} to check whether it is 'undefined' and not add % in the end ?
Or is there any other way and I am doing it wrong?
Basically something like -
series.legendSettings.itemValueText = "{valueY}";
if (series.legendSettings.itemValueText !== undefined) { // or check {valueY}
series.legendSettings.itemValueText = "[bold]{valueY}%[/]"; // Only if value is undefined add % in last
series.legendSettings.valueText = "(Avg: [bold]{valueY.average.formatNumber('#.##')}%[/])";
}
You can create a textOutput adapter on the legend's valueLabels template to check the final text output based on your template string and adjust accordingly.
chart.legend.valueLabels.template.adapter.add("textOutput", function(text, target) {
if (text === '(Avg: [bold]%[/])') {
return 'N/A';
}
else if (text === '[bold]%[/]') {
return '';
}
return text;
});
Demo

Javascript to change values in stylesheets

I'm looking to find a way to change every instance of a color in stylesheets that get loaded into a site. I'm working with Prestashop and working with large theme style sheets and modules' stylesheets... so I'm looking to change font colors and background colors. Yes I can do a search and replace... but I'd like to have reusable code that I can use on multiple sites and multiple files and themes.
I've been checking out a bunch of articles on here and found some code that selects all the elements loaded and checks the ComputedStyle and if it equals one value, it changes it to a new value.
function colorToHex(color) {
if (color.substr(0, 1) === '#') {
return color;
}
var digits = /(.*?)rgb\((\d+), (\d+), (\d+)\)/.exec(color);
var red = parseInt(digits[2]);
var green = parseInt(digits[3]);
var blue = parseInt(digits[4]);
var rgb = blue | (green << 8) | (red << 16);
return digits[1] + '#' + rgb.toString(16);
};
function changeColor(from, to) {
var elements = document.getElementsByTagName('*');
var to = '#babaff';
var from = '#f66685';
for (var i=0;i<elements.length;i++) {
var color = window.getComputedStyle(elements[i]).color;
var hex = colorToHex(color);
console.log('color=' ,color, elements[i]);
if (hex == from) {
elements[i].style.color=to;
console.log('its a color match!', elements[i]);
}
var backgroundColor = window.getComputedStyle(elements[i]).background;
console.log('bgcolor=' ,backgroundColor);
if (backgroundColor.indexOf('rgba')<0) {
var hex = colorToHex(backgroundColor);
if (hex == from) {
elements[i].style.backgroundColor=to;
}
}
}
}
It's partially working, but doesn't seem to work on conditional values... like hover or active states. So ideally I'm just looking for something that just finds a string of text (the hex code) and changes it out... and it doesn't care what the element is (class, tag, id) and doesn't matter the rule (background, background-color, color, border, ect) because these themes are pre-built and not standardized.
As you stated:
"ideally I'm just looking for something that just finds a string of text (the hex code) and changes it out"
Thats basically what a search and replace does. (besides the hex stuff)
If you are looking at a problem like replacing a single color in your whole style, and it is very time consuming atm, then you are probably doing something wrong.
As #delinear mentions in his comment, you probably want to use a sass script.
Using some javascript to change all colors after the css has already loaded is performance heavy and not really the way to do it.
I would really suggest a Search&Replace and to use sass variables afterwards.
(If you maybe want to change colors again)
there you can just do something like
$color: #ff00ff;
h1{
background-color: $color;
}
h2{
color: $color;
}
h3{
background: linear-gradient(135deg, red, $color);
}
h2:hover{
color: $color;
}

Get real value of a CSS color property in script

When I use window.getComputedStyle on an element's color property, it returns a string with an rgb() or rgba() value, regardless of the syntax used to set the color originally. In Internet Explorer, when forced to use element.currentStyle instead, it apparently returns the exact color string that was originally set (although lowercased).
Here is a demonstration of my problem:
<div id=el> </div>
<script type="text/javascript">
var el = document.getElementById('el');
el.style.color = 'red';
if (window.getComputedStyle) {
el.innerHTML = getComputedStyle(el, null).color;
} else {
el.innerHTML = el.currentStyle.color;
}
</script>
Other browsers display "rgb(255, 0, 0)". IE displays "red". I want to determine the real RGB or RGBA value. So I have two questions:
Is there any way to get the real value in IE... other than by parsing all potential color syntaxes manually and including a mapping of color names to values?
Could the behavior of the other browsers be relied on? Are they supposed to return a value as an rgb() or rgba() string, or could they return, for example, #ff0000, or something else?
As best I can tell, the answer is "no". There is no simple way to get the color value in IE without knowing how to parse all possible color representations. When I tried to do this, I found that I even needed to recognized all possible color names like blue. It was a royal pain, but I did work out the code for it.
My code was trying to get the background color and it will even look at parent objects in order to find where the background color is set (so it's not doing exactly what you asked for) and it used the YUI version of getComputedStyle (you can substitute your own) but this is the code I used. It does handle these forms of color definition:
#fff
#ffffff
transparent
rgb(12,45,99)
rgba(12,45,99,30)
orange
And, the code:
JFL.GetBackgroundColor = function(o)
{
var colorNames = {
aliceblue: 'f0f8ff',
antiquewhite: 'faebd7',
aqua: '00ffff',
aquamarine: '7fffd4',
azure: 'f0ffff',
beige: 'f5f5dc',
bisque: 'ffe4c4',
black: '000000',
blanchedalmond: 'ffebcd',
blue: '0000ff',
blueviolet: '8a2be2',
brown: 'a52a2a',
burlywood: 'deb887',
cadetblue: '5f9ea0',
chartreuse: '7fff00',
chocolate: 'd2691e',
coral: 'ff7f50',
cornflowerblue: '6495ed',
cornsilk: 'fff8dc',
crimson: 'dc143c',
cyan: '00ffff',
darkblue: '00008b',
darkcyan: '008b8b',
darkgoldenrod: 'b8860b',
darkgray: 'a9a9a9',
darkgreen: '006400',
darkkhaki: 'bdb76b',
darkmagenta: '8b008b',
darkolivegreen: '556b2f',
darkorange: 'ff8c00',
darkorchid: '9932cc',
darkred: '8b0000',
darksalmon: 'e9967a',
darkseagreen: '8fbc8f',
darkslateblue: '483d8b',
darkslategray: '2f4f4f',
darkturquoise: '00ced1',
darkviolet: '9400d3',
deeppink: 'ff1493',
deepskyblue: '00bfff',
dimgray: '696969',
dodgerblue: '1e90ff',
feldspar: 'd19275',
firebrick: 'b22222',
floralwhite: 'fffaf0',
forestgreen: '228b22',
fuchsia: 'ff00ff',
gainsboro: 'dcdcdc',
ghostwhite: 'f8f8ff',
gold: 'ffd700',
goldenrod: 'daa520',
gray: '808080',
green: '008000',
greenyellow: 'adff2f',
honeydew: 'f0fff0',
hotpink: 'ff69b4',
indianred : 'cd5c5c',
indigo : '4b0082',
ivory: 'fffff0',
khaki: 'f0e68c',
lavender: 'e6e6fa',
lavenderblush: 'fff0f5',
lawngreen: '7cfc00',
lemonchiffon: 'fffacd',
lightblue: 'add8e6',
lightcoral: 'f08080',
lightcyan: 'e0ffff',
lightgoldenrodyellow: 'fafad2',
lightgrey: 'd3d3d3',
lightgreen: '90ee90',
lightpink: 'ffb6c1',
lightsalmon: 'ffa07a',
lightseagreen: '20b2aa',
lightskyblue: '87cefa',
lightslateblue: '8470ff',
lightslategray: '778899',
lightsteelblue: 'b0c4de',
lightyellow: 'ffffe0',
lime: '00ff00',
limegreen: '32cd32',
linen: 'faf0e6',
magenta: 'ff00ff',
maroon: '800000',
mediumaquamarine: '66cdaa',
mediumblue: '0000cd',
mediumorchid: 'ba55d3',
mediumpurple: '9370d8',
mediumseagreen: '3cb371',
mediumslateblue: '7b68ee',
mediumspringgreen: '00fa9a',
mediumturquoise: '48d1cc',
mediumvioletred: 'c71585',
midnightblue: '191970',
mintcream: 'f5fffa',
mistyrose: 'ffe4e1',
moccasin: 'ffe4b5',
navajowhite: 'ffdead',
navy: '000080',
oldlace: 'fdf5e6',
olive: '808000',
olivedrab: '6b8e23',
orange: 'ffa500',
orangered: 'ff4500',
orchid: 'da70d6',
palegoldenrod: 'eee8aa',
palegreen: '98fb98',
paleturquoise: 'afeeee',
palevioletred: 'd87093',
papayawhip: 'ffefd5',
peachpuff: 'ffdab9',
peru: 'cd853f',
pink: 'ffc0cb',
plum: 'dda0dd',
powderblue: 'b0e0e6',
purple: '800080',
red: 'ff0000',
rosybrown: 'bc8f8f',
royalblue: '4169e1',
saddlebrown: '8b4513',
salmon: 'fa8072',
sandybrown: 'f4a460',
seagreen: '2e8b57',
seashell: 'fff5ee',
sienna: 'a0522d',
silver: 'c0c0c0',
skyblue: '87ceeb',
slateblue: '6a5acd',
slategray: '708090',
snow: 'fffafa',
springgreen: '00ff7f',
steelblue: '4682b4',
tan: 'd2b48c',
teal: '008080',
thistle: 'd8bfd8',
tomato: 'ff6347',
turquoise: '40e0d0',
violet: 'ee82ee',
violetred: 'd02090',
wheat: 'f5deb3',
white: 'ffffff',
whitesmoke: 'f5f5f5',
yellow: 'ffff00',
yellowgreen: '9acd32'
};
function parseSingle(s)
{
s = s + s;
return(parseInt(s, 16));
}
var color;
while (o)
{
color = YD.getComputedStyle(o, "backgroundColor");
if (color && color != "transparent")
{
break;
}
if (o == document.body)
{
color = "#ffffff";
break;
}
o = o.parentNode;
}
color = color.replace(/ /g, "").toLowerCase();
if (colorNames[color])
{
color = "#" + colorNames[color];
}
var r = 256, g = 256, b = 256;
if (color.indexOf("#") == 0)
{
color = color.slice(1);
if (color.length == 3)
{
r = parseSingle(color.slice(0,1));
g = parseSingle(color.slice(1,2));
b = parseSingle(color.slice(2,3));
}
else if (color.length == 6)
{
r = parseInt(color.slice(0,2), 16);
g = parseInt(color.slice(2,4), 16);
b = parseInt(color.slice(4,6), 16);
}
}
else if (color.indexOf("rgb") == 0)
{
var results = color.match(/^rgba?\((\d{1,3}),\s*(\d{1,3}),\s*(\d{1,3})/);
if (results && results.length >= 4)
{
r = parseInt(results[1], 10);
g = parseInt(results[2], 10);
b = parseInt(results[3], 10);
}
}
var luminance = (0.3 * r + 0.59 * g + 0.11 * b) / 256;
return({r: r, g: g, b: b, luminance: luminance});
}
As suggested I examined CMS's answer here which uses queryCommandValue. For the equivalent of CSS 'color' rather than 'backround-color', I had to use 'ForeColor' rather than 'BackColor', but this technique seems to work perfectly for getting the real value in IE.
Here is the amended, working version of the example in my question:
<div id=el> </div>
<script type="text/javascript">
var el = document.getElementById('el');
el.style.color = 'red';
if (window.getComputedStyle) {
el.innerHTML = getComputedStyle(el, null).color;
} else {
var oRG = document.body.createTextRange();
oRG.moveToElementText(el);
var iClr = oRG.queryCommandValue('ForeColor');
el.innerHTML = 'rgb('+(iClr & 0xFF)+','+((iClr & 0xFF00)>>8)+','+((iClr & 0xFF0000)>>16)+')';
}
</script>
I've been looking for an answer to my second question, but there doesn't seem to be one. If I'm reading it correctly, this page: http://www.w3.org/TR/css3-color/ explains that browsers may return, for the computed value, either a "six digit hex value or rgb(...) functional value, with an alpha value of 1" (?). It says transparent returns rgba(0,0,0,0). And finally it says, "for all other values, the computed value is the specified value". This is not clear at all. E.g., must it use RGB integers or can it use percentages? May there be space around the values? Can the "specified value"'s letter case be preserved? What about hsl() and hsla() colors?
In practice, it seems that browsers normalize the values to return rgb(...) or rgba(...), with the red-green-blue as integers and the alpha as a decimal, with a single space after each comma, although this doesn't seem to be formally specified. As an exception, Firefox seems to return transparent if the color's alpha value is 0, regardless of the other values or how it was set; e.g., rgba(255, 0, 255, 0).
So, IE's odd way for getting an RGB int is far simpler, if you can use it.

How to compare colors in JavaScript?

Why doesn't this work? Even though the colour is equal to #ECECF4 it still alerts "No".
It is selecting the corrent element as I have tested it. Is there a better way to write this?
<script type="text/javascript">
function weekclick() {
if (document.getElementById('w1').style.backgroundColor == "#ECECF4") {
alert("Yes");
} else {
alert("No");
}
}
</script>
Comparing colors as part of the business logic should be avoided at all cost.
Instead, keep the logic in JavaScript and act according to a state kept somewhere. Then, if you want to send a visual feedback to the user through a change of color, add a class to the element. That way, JavaScript only knows about class names and the styling is always isolated in the CSS as it should.
$(".list").on("click", "li", function(){
$(this).toggleClass('active');
});
.list {
width: 100%;
padding: 0;
}
.list li {
padding: 5px 10px;
list-style: none;
cursor: pointer;
}
.list li:hover {
background-color: rgba(0, 0, 0, 0.05);
}
.list li.active {
background-color: #eeeecc;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<ul class="list">
<li>test 1</li>
<li>test 2</li>
<li>test 3</li>
</ul>
That being said, OP's code works for me with Chrome 17.0.963.56 and Firefox 8.0. When you don't know what to compare, just use console.log() to see what it looks like.
Note that #ECECF4 is the same color as rgb(236, 236, 244) but in a different representation.
IE7 and IE8 output the HEX value, IE9 and up and other browsers output the RGB format. So comparing color with cross-browser compatibility is a tricky task and the best way to do it isn't beautiful.
I made a simple function which works for most cases with most browser, even with color set through CSS.
function weekclick() {
var elemColor = getStyle(this, "backgroundColor"),
color = "rgb(238, 238, 204)";
console.log("Broswer returned elem color: ", elemColor);
// IE7 and IE8 output the hex value
if (elemColor.slice(0, 1) === '#') elemColor = hexToRgb(elemColor);
console.log(elemColor, " === ", color, "?", elemColor === color);
}
// Source: https://stackoverflow.com/a/41354868/1218980
// Inspired by: https://stackoverflow.com/a/22744598/1218980
function getStyle(el, prop) {
return (typeof getComputedStyle !== 'undefined' ?
getComputedStyle(el, null) :
el.currentStyle
)[prop];
}
// Slightly modified version to quickly return a string
// https://stackoverflow.com/a/5624139/1218980
function hexToRgb(hex) {
// Expand shorthand form (e.g. "03F") to full form (e.g. "0033FF")
var shorthandRegex = /^#?([a-f\d])([a-f\d])([a-f\d])$/i;
hex = hex.replace(shorthandRegex, function(m, r, g, b) {
return r + r + g + g + b + b;
});
var result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);
return result ? "rgb(" + [
parseInt(result[1], 16),
parseInt(result[2], 16),
parseInt(result[3], 16)
].join(', ') + ")" : null;
}
#css-div {
background-color: #eeeecc;
}
<div style="Background-color:#eeeecc" onclick="javascript:weekclick.call(this);">#eeeecc</div>
<div style="Background-color:#EEC" onclick="javascript:weekclick.call(this);">#EEC</div>
<div style="background-color:hsla(60, 50%, 86.7%, 1)" onclick="javascript:weekclick.call(this);">hsla(60, 50%, 86.7%, 1)</div>
<div style="background-color:rgb(238, 238, 204)" onclick="javascript:weekclick.call(this);">rgb(238, 238, 204)</div>
<div id="css-div" onclick="javascript:weekclick.call(this);">css</div>
I call the weekclick function with javascript:weekclick.call(this) passing the element itself as the context of the callback, making it easy to access the element with this.
It could be extended to take alpha into account when using HSLA or RGBA.
When I originally wrote this answer back in 2012, I used navigator.appName === "Microsoft Internet Explorer" to know if it was IE7 and the color to compare was changed to its HEX equivalent. Don't do that as it won't work today.
Use a canvas to compare colors.
Fill one pixel using the color string
and the other pixel using the Element getComputedStyle color property.
Compare the two pixels data using Array.from and JSON.stingify
/**
* Test if Element color property holds a specific color.
* https://stackoverflow.com/a/60689673/383904
*
* #param {Object} el The DOM Node Element
* #param {String} prop A CSS property color property
* #param {String} color A valid CSS color value
* #return {Boolean} True if element color matches
*/
function isElPropColor(el, prop, color) {
const ctx = document.createElement('canvas').getContext('2d');
ctx.fillStyle = color;
ctx.fillRect( 0, 0, 1, 1 );
ctx.fillStyle = getComputedStyle(el, null).getPropertyValue(prop);
ctx.fillRect( 1, 0, 1, 1 );
const a = JSON.stringify(Array.from(ctx.getImageData(0, 0, 1, 1).data));
const b = JSON.stringify(Array.from(ctx.getImageData(1, 0, 1, 1).data));
ctx.canvas = null;
return a === b;
}
// TEST (PS: see CSS!):
const el = document.body;
const prop = 'background-color';
console.log(isElPropColor(el, prop, 'red')); // obviously true :)
console.log(isElPropColor(el, prop, '#f00')); // true
console.log(isElPropColor(el, prop, 'rgb(255, 0, 0)')); // true
console.log(isElPropColor(el, prop, 'hsl(0, 100%, 50%)')); // true
console.log(isElPropColor(el, prop, 'hsla(0, 100%, 50%, 1)')); // true
body {background: red; }
The buts and whys
Most modern browsers calculate and convert the color value to RGB/A.
But we should not rely on doing strict equality comparison like:
// (Say the element is really red)
const isRed = myElement.style.backgroundColor === "rgb(255,0,0)"; // false
False because it's actually "rgb(255, 0, 0)", with spaces.
No guarantee some browser tomorrow will not convert to "rgba(255, 0, 0, 1)", or HSLA perhaps?
Edge and IE will return the value used in CSS or overwritten by our JS
We cannot reliably compare two DIV styles using getComputedStyle
and we cannot even create an "in-memory" DIV element since we need to - append it to the DOM, than use getComputedStyle(tempDIVElement, null).getPropertyValue('background-color') and than remove it from the DOM. It's a waste of DOM recalculations, paints, and it's not guaranteed some wondering stylesheet !important did not messed up our temporary DIV styles div {background: fuchsia !important; } giving false-positives "Is red? True! blue is blue because of !important".
Why canvas?
A canvas can stay in memory. No need to append to DOM, set colors, remove element.
The returned pixel data is always guaranteed to be [R, G, B, A] (RGBA being 0-255 values)
A wondering CSS rule will not mess up the assigned color
Useful links:
Canvas_API MDN
CanvasRenderingContext2D/getImageData MDN
Array/from MDN
JSON/stringify MDN
Window/getComputedStyle MDN
I'm actually just learning javascript, but instead of creating a function that converted rgb() to hex you can create a div of the same background-color you are looking for and compared it to that div's background color. If you happen to already have a div of that hex value you can just do this:
//javascript
if (document.getElementId('desiredElementToCompare').style.backgroundColor === document.getElementId('elementWithTheDesiredHexString').style.backgroundColor)
//jQuery
if ($('#desiredElementToCompare').css('background-color') === $('#elementWithTheDesiredHexString').css('background-color')
You can create a div with a function and then do the comparison like this:
var compareHex = (hex) => {
var hexString = document.createElement('div')
hexString.style.backgroundColor = `${hex}`
return hexString.style.backgroundColor
}
//then compare
//javascript
if (document.getElementId('desiredElementToCompare').style.backgroundColor === compareHex("#ECECF4"))
//jQuery
if($('#desiredElementToCompare').css('background-color') === compareHex("#ECECF4")
This way suggests using JQuery's background-color which standardises the response to rgb(r, g, b).
How to get the background color of an element using javascript?
Maybe this answer could help. Convert the color code to hex and then compare each RGB color/channel (i don't know the word)
https://stackoverflow.com/a/25666938/1757214
I think is better and easy compare two numbers than two strings
I would advice using the '===' stric equal (i think this is the name).
Like:
if (document.getElementById('test').style.backgroundColor === "rgb(236, 236, 244)") {

Categories

Resources