0

I want to change the font color based on the color of the image. The font color must be black or white, but it should change proportionally to the color of the image as it does in the code below.

So, I have this js function that if you move the mouse it changes the background color and consequently also the text (in the snippet move the pointer under the background). Obviously the part where you move the mouse to change color doesn't interest me, it's just a test. Is there a way to apply the function to my personal div?

In simple terms I want the color of the text to change based on my background and not if you move the mouse. Sorry for the poor explanation, I'm relatively new here, trying to learn how to exercise this function. Currently I don't know how to do it, I appreciate any answer, thanks.

function getTextColor(rgba){
  rgba = rgba.match(/\d+/g);
  if((rgba[0]*0.299)+(rgba[1]*0.587)+(rgba[2]*0.114)>186) {
    return 'black';
  } else {
    return 'white';
  }
}

var div = document.createElement('div');
div.style.height = '100vh';
document.body.appendChild(div);

div.addEventListener('mousemove', (event)=>{
  var x = event.clientX;
  var y = event.clientY;
  div.textContent = `${x} , ${y}`;
  div.style.backgroundColor = `rgba(${x},${y},100,100)`;
  div.style.color = getTextColor(div.style.backgroundColor);
});
.background {
  height: 100vh;
  background: url("https://i.pinimg.com/originals/bc/a3/2d/bca32d5cdfabeaeb4faeb12bff160524.jpg");
}
<div class="background">Background example</div>

3
  • 1
    To clarify, You would like to take the average color of the background and change the text color to either black or white depending on said average, correct? Commented Jul 26, 2022 at 0:32
  • That's right, I'd like to take the medium color of the background. I think it's the right thing to do. This way the text should turn white if the background is too dark, or turn black if it is too light. Note, in my css the background is determined by background-image and not background-color. Commented Jul 26, 2022 at 0:45
  • It seems that this is not a fully supported functionality, but it does the job. This thread explains it Commented Jul 26, 2022 at 0:55

1 Answer 1

2

Explanation


Here is an example showing how to get the average using a canvas rendered to a 1x1-px scale. From there we set the header background and then apply a light or dark class based on the luminance of the aforementioned average.

Notes


Note 1: There is some extra code to allow for easier visualization, this is commented and can be removed.

Note 2: The below code is not guaranteed to run on all browsers. Please see this thread for more specifics.

Note 3: This code only works with local images and CORS-enabled image URLs due to it's reliance on canvas.drawImage. Please see this for more information.

Example 1:

this example shows the functionality. It uses two image URLs in the JS to toggle between.

/* 
     
     THE TOGGLE ACTION
     
     */

/* The urls for toggling between */
const urlLight = 'https://images.unsplash.com/photo-1484503793037-5c9644d6a80a?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=930&q=80';
const urlDark = 'https://images.unsplash.com/photo-1517999144091-3d9dca6d1e43?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=627&q=80';
let currentUrl = urlLight;

const toggle = document.getElementById('toggle');

toggle.addEventListener("click", function() {
  if (currentUrl === urlLight) {
    currentUrl = urlDark;
  } else {
    currentUrl = urlLight;
  }

  getImageBrightness(currentUrl, function(brightness) {

    const header = document.getElementById("header");
    header.style.backgroundImage = `url(${currentUrl}`;

    header.classList.remove("dark");
    header.classList.remove("light");

    console.log(brightness);

    if (brightness > 225 / 2) {
      header.classList.toggle("dark");

    } else {
      header.classList.toggle("light");
    }
  });

});

/* 

Important get brightness code

*/

function getImageBrightness(imageSrc, callback) {
  var img = document.createElement("img");
  img.src = imageSrc;
  img.style.display = "none";
  img.crossOrigin = "anonymous";
  document.body.appendChild(img);

  var colorSum = 0;

  img.onload = function() {
    // create canvas
    var canvas = document.createElement("canvas");
    canvas.width = this.width;
    canvas.height = this.height;

    var ctx = canvas.getContext("2d");
    ctx.drawImage(this, 0, 0);

    var imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
    var data = imageData.data;
    var r, g, b, avg;

    for (var x = 0, len = data.length; x < len; x += 4) {
      r = data[x];
      g = data[x + 1];
      b = data[x + 2];

      avg = Math.floor((r + g + b) / 3);
      colorSum += avg;
    }

    var brightness = Math.floor(colorSum / (this.width * this.height));
    callback(brightness);
  }
}



getImageBrightness(currentUrl, function(brightness) {

  const header = document.getElementById("header");
  header.style.backgroundImage = `url(${currentUrl}`;

  header.classList.remove("dark");
  header.classList.remove("light");


  if (brightness > 225 / 2) {
    header.classList.toggle("dark");

  } else {
    header.classList.toggle("light");
  }
});
.dark {
  color: black;
}

.light {
  color: white;
}

* {
  text-align: center;
}

#header {
  padding: 2rem 0;
  font-size: 4rem;
  background-size: cover;
  margin-bottom: 1rem;
  background-position: center center;
}
<div id="header">
  Header
</div>

<button id='toggle'>
Toggle Background
</button>

Example 2:

This example directly answers the question by retrieving the background image of the current div and running the function using said image.

/* 

Important get brightness code

*/

function getImageBrightness(imageSrc, callback) {
  var img = document.createElement("img");
  img.src = imageSrc;
  img.style.display = "none";
  img.crossOrigin = "anonymous";
  document.body.appendChild(img);

  var colorSum = 0;

  img.onload = function() {
    // create canvas
    var canvas = document.createElement("canvas");
    canvas.width = this.width;
    canvas.height = this.height;

    var ctx = canvas.getContext("2d");
    ctx.drawImage(this, 0, 0);

    var imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
    var data = imageData.data;
    var r, g, b, avg;

    for (var x = 0, len = data.length; x < len; x += 4) {
      r = data[x];
      g = data[x + 1];
      b = data[x + 2];

      avg = Math.floor((r + g + b) / 3);
      colorSum += avg;
    }

    var brightness = Math.floor(colorSum / (this.width * this.height));
    callback(brightness);
  }
}


/* The element we wish to work on */
const header = document.getElementById("header");

/* To get the background image. Get style and then background image with a slice to remove quotes */
var imageElement = document.getElementById('header'),
  style = imageElement.currentStyle || window.getComputedStyle(imageElement, false),
  backgroundImage = style.backgroundImage.slice(4, -1).replace(/"/g, "");



getImageBrightness(backgroundImage, function(brightness) {
  /* Remove dark and light classes from the element */
  header.classList.remove("dark");
  header.classList.remove("light");

  /* check brightness and apply correct style */
  /* Please modify the below brightness comparison statement to adjust to your needs */
  if (brightness > 225 / 2) {
    header.classList.toggle("dark");

  } else {
    header.classList.toggle("light");
  }
});
.dark {
  color: black;
}

.light {
  color: white;
}

* {
  text-align: center;
}

#header {
  padding: 2rem 0;
  font-size: 4rem;
  background-size: cover;
  margin-bottom: 1rem;
  background-position: center center;
  background-image: url('https://images.unsplash.com/photo-1530128118208-89f6ce02b37b?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=1740&q=80')
}
<div id="header">
  <h1>
    Header
  </h1>
</div>

Sign up to request clarification or add additional context in comments.

6 Comments

Thanks for your time, that's exactly what I was trying to do. However, I have a concern. How do I apply the function to a personal div? I have several pages with different backgrounds, so instead of toggle the function it should reveal the background image I have in the div. I'm trying with the code you wrote but I can't.
I see that the url of the images have been put in the js code while my images are in html code or put with css background-image, there is a way to tell the function that it must read the image from my div or from the css and instead of putting them directly in the js code?
I have updated the answer with a more direct example of how to implement this.
Thanks so much, I am grateful for that. Now that I have several examples, I'll do some practice and practice on these references. Thanks again.
The easiest way to ensure this works is to use local images from your web server since CORS only deals with external sources. Attempting to use it on CORS disabled URLs is a security threat and should not be tried.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.