MagicMirror Forum
    • Recent
    • Tags
    • Unsolved
    • Solved
    • MagicMirror² Repository
    • Documentation
    • 3rd-Party-Modules
    • Donate
    • Discord
    • Register
    • Login
    A New Chapter for MagicMirror: The Community Takes the Lead
    Read the statement by Michael Teeuw here.

    Dynamic Font Colors

    Scheduled Pinned Locked Moved Custom CSS
    8 Posts 3 Posters 459 Views 4 Watching
    Loading More Posts
    • Oldest to Newest
    • Newest to Oldest
    • Most Votes
    Reply
    • Reply as topic
    Log in to reply
    This topic has been deleted. Only users with topic management privileges can see it.
    • I Offline
      ijoshea
      last edited by

      I’m using MMM-GooglePhotos for revolving background images and depending on the color of the image show the font on modules displaying over the image can be hard to read.

      I’ve been trying to get custom.css to handle this by using colorthief (https://lokeshdhakar.com/projects/color-thief/) to determine if the image is light or dark and to set a contrasting color palette.

      I don’t have a lot experience with CSS/JS should this be doable?

      Here is the code I have tried to date but the @import on the custom.css gets an error, “This page failed to load a stylesheet from a URL.”
      This is currently aimed at MMM-CalendarExt3 which is most used for me.

      /* custom.css code
      @import url('https://cdnjs.cloudflare.com/ajax/libs/color-thief/2.3.2/color-thief.min.js');
      
      body::after {
        content: '';
        display: none;
        /* Ensure the external script is loaded before running the adaptiveFontColor.js script */
        background-image: url('modules/MMM-GooglePhotos/adaptiveFontColor.js');
      }
      // adaptiveFontColor.js
      
      function isColorDark(rgbColor) {
          const [r, g, b] = rgbColor;
          // Calculate luminance
          const luminance = 0.2126 * r + 0.7152 * g + 0.0722 * b;
          return luminance < 128;
      }
      
      function applyAdaptiveFontColor(imageElement, targetElements) {
          const colorThief = new ColorThief();
          const dominantColor = colorThief.getColor(imageElement);
          console.log('Dominant Color:', dominantColor); // Log the dominant color
          const isDark = isColorDark(dominantColor);
      
          const fontColor = isDark ? 'white' : 'black';
          const textShadow = isDark ? '0 0 5px rgba(0,0,0,0.8)' : '0 0 5px rgba(255,255,255,0.8)';
      
          console.log('Font Color:', fontColor); // Log the font color
          console.log('Text Shadow:', textShadow); // Log the text shadow
      
          targetElements.forEach(element => {
              element.style.color = fontColor;
              element.style.textShadow = textShadow;
              console.log('Applied styles to:', element); // Log the element being styled
          });
      }
      
      function setupObserver(imageSelector, targetSelector) {
          const imageElement = document.querySelector(imageSelector);
          const targetElements = document.querySelectorAll(targetSelector);
      
          console.log('Image Element:', imageElement); // Log the image element
          console.log('Target Elements:', targetElements); // Log the target elements
      
          if (imageElement) {
              const observer = new MutationObserver((mutations) => {
                  console.log('Mutation observed:', mutations); // Log mutations
                  if (imageElement.complete) {
                      applyAdaptiveFontColor(imageElement, targetElements);
                      console.log('Image complete');
                  } else {
                      imageElement.addEventListener('load', () => {
                          applyAdaptiveFontColor(imageElement, targetElements);
                          console.log('Image loaded');
                      });
                  }
              });
      
              observer.observe(imageElement, {
                  attributes: true,
                  attributeFilter: ['src']
              });
      
              // Initial check in case the image is already loaded
              if (imageElement.complete) {
                  applyAdaptiveFontColor(imageElement, targetElements);
                  console.log('Initial image complete');
              } else {
                  imageElement.addEventListener('load', () => {
                      applyAdaptiveFontColor(imageElement, targetElements);
                      console.log('Initial image loaded');
                  });
              }
          } else {
              console.log('Image element not found with selector:', imageSelector);
          }
      }
      
      // Wait for the document to load
      window.addEventListener('load', function() {
          console.log('Document loaded'); // Log document load event
          const imageSelector = '#GPHOTO_CURRENT'; // Updated selector for the image
          const targetSelector = '.CX3A .event .headline'; // Adjusted selector for calendar events
      
          setupObserver(imageSelector, targetSelector);
      });
      

      Any help would be appreciated.

      S M 5 Replies Last reply Reply Quote 0
      • S Away
        sdetweil @ijoshea
        last edited by sdetweil

        @ijoshea id like this too. if you ope the developers window you should see your script loaded and be able to debug it
        I think you might need the full url

        http://localhost:mm_port/modules....
        

        Sam

        How to add modules

        learning how to use browser developers window for css changes

        1 Reply Last reply Reply Quote 0
        • M Offline
          MMRIZE @ijoshea
          last edited by MMRIZE

          @ijoshea
          It seems weird to import JS in css.

          S 1 Reply Last reply Reply Quote 0
          • S Away
            sdetweil @MMRIZE
            last edited by

            @MMRIZE AND it doesn’t work…

            Sam

            How to add modules

            learning how to use browser developers window for css changes

            1 Reply Last reply Reply Quote 0
            • S Away
              sdetweil @ijoshea
              last edited by sdetweil

              @ijoshea I added the scripts to MMM-ImagesPhotos (getScripts response)
              and they are loaded… BUT the document on(‘load’) from the script above doesn’t fire…
              I don’t know if that is because in my version of MMM-ImagesPhotos I set an onload for each image loaded so that I can adjust the size to keep the aspect ratio from the image
              (css cover and contain both adjust the aspect ratio)

              Sam

              How to add modules

              learning how to use browser developers window for css changes

              1 Reply Last reply Reply Quote 0
              • M Offline
                MMRIZE @ijoshea
                last edited by MMRIZE

                @ijoshea
                I had the same needs on building modules. (btw, GooglePhotos and CX3 were built by me :D )

                Sometimes I suggested other module’s background for the readability. Sometimes, I made an auto-calculated contrast color(e.g. CX3)

                My final conclusion is… waiting for new CSS feature contrast-color(). It will be introduced later this year in the most modern browsers.
                https://drafts.csswg.org/css-color-5/#contrast-color

                1 Reply Last reply Reply Quote 1
                • M Offline
                  MMRIZE @ijoshea
                  last edited by

                  @ijoshea
                  Anyway, It looks so interesting, So I tried something. I simply did monkey patching to get dominant color from MMM-GooglePhotos’s image on load.

                  6e971ed4-d102-434d-98e3-fd9d1de48374-image.png
                  You can do your job with this code without modifying the source codes itselfs.

                  /* config/config.js */
                  {
                  	module: "MMM-ModuleMonkeyPatch",
                  	config: {
                  		patches: [
                  			{
                  				module: "MMM-GooglePhotos",
                  				method: "ready",
                  				patch: async function (original, [ url, target ]) {
                  					const ret = original(url, target)
                  					let color = null
                  					const process = async () => {
                  						const { resolve, promise } = Promise.withResolvers()
                  						const img = new Image()
                  						img.crossOrigin = 'Anonymous'
                  						img.src = 'https://corsproxy.io/?' + url
                  						img.onload = () => {
                  							const colorThief = new ColorThief()
                  							const color = colorThief.getColor(img)
                  							resolve(color)
                  						}
                  						return promise
                  					}
                  					if (typeof ColorThief === 'undefined') {
                  						const loadScript = async (src) => {
                  							const { resolve, promise } = Promise.withResolvers()
                  							const script = document.createElement('script')
                  							script.src = src
                  							document.head.appendChild(script)
                  							script.onload = () => resolve()
                  							return promise
                  						}
                  						await loadScript('https://cdn.jsdelivr.net/npm/colorthief@2/dist/color-thief.min.js')
                  						color = await process()
                  
                  					} else {
                  						color = await process()
                  					}
                  
                  					console.log(color) // It will show [R, G, B] array
                  					// doYourJob(color)
                  
                  					return ret
                  				},
                  			},
                  		],
                  	},
                  },
                  
                  I 1 Reply Last reply Reply Quote 1
                  • I Offline
                    ijoshea @MMRIZE
                    last edited by

                    @MMRIZE @sdetweil thanks for the help. I havent had a chance to play around with it on my set up but looks to be going in the right direction!

                    1 Reply Last reply Reply Quote 0
                    • 1 / 1
                    • First post
                      Last post
                    Enjoying MagicMirror? Please consider a donation!
                    MagicMirror created by Michael Teeuw.
                    Forum managed by Sam, technical setup by Karsten.
                    This forum is using NodeBB as its core | Contributors
                    Contact | Privacy Policy