<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[Dynamic Font Colors]]></title><description><![CDATA[<p dir="auto">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.</p>
<p dir="auto">I’ve been trying to get custom.css to handle this by using colorthief (<a href="https://lokeshdhakar.com/projects/color-thief/" target="_blank" rel="noopener noreferrer nofollow ugc">https://lokeshdhakar.com/projects/color-thief/</a>) to determine if the image is light or dark and to set a contrasting color palette.</p>
<p dir="auto">I don’t have a lot experience with CSS/JS should this be doable?</p>
<p dir="auto">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.”<br />
This is currently aimed at MMM-CalendarExt3 which is most used for me.</p>
<pre><code>/* 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 &lt; 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 =&gt; {
        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) =&gt; {
            console.log('Mutation observed:', mutations); // Log mutations
            if (imageElement.complete) {
                applyAdaptiveFontColor(imageElement, targetElements);
                console.log('Image complete');
            } else {
                imageElement.addEventListener('load', () =&gt; {
                    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', () =&gt; {
                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);
});
</code></pre>
<p dir="auto">Any help would be appreciated.</p>
]]></description><link>https://forum.magicmirror.builders/topic/18862/dynamic-font-colors</link><generator>RSS for Node</generator><lastBuildDate>Mon, 11 May 2026 22:09:13 GMT</lastBuildDate><atom:link href="https://forum.magicmirror.builders/topic/18862.rss" rel="self" type="application/rss+xml"/><pubDate>Sun, 07 Jul 2024 07:49:40 GMT</pubDate><ttl>60</ttl><item><title><![CDATA[Reply to Dynamic Font Colors on Thu, 11 Jul 2024 00:09:22 GMT]]></title><description><![CDATA[<p dir="auto"><a class="plugin-mentions-user plugin-mentions-a" href="/user/mmrize" aria-label="Profile: MMRIZE">@<bdi>MMRIZE</bdi></a> <a class="plugin-mentions-user plugin-mentions-a" href="/user/sdetweil" aria-label="Profile: sdetweil">@<bdi>sdetweil</bdi></a> 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!</p>
]]></description><link>https://forum.magicmirror.builders/post/118815</link><guid isPermaLink="true">https://forum.magicmirror.builders/post/118815</guid><dc:creator><![CDATA[ijoshea]]></dc:creator><pubDate>Thu, 11 Jul 2024 00:09:22 GMT</pubDate></item><item><title><![CDATA[Reply to Dynamic Font Colors on Mon, 08 Jul 2024 11:57:48 GMT]]></title><description><![CDATA[<p dir="auto"><a class="plugin-mentions-user plugin-mentions-a" href="/user/ijoshea" aria-label="Profile: ijoshea">@<bdi>ijoshea</bdi></a><br />
Anyway, It looks so interesting, So I tried something. I simply did monkey patching to get dominant color from <code>MMM-GooglePhotos</code>’s image on load.</p>
<p dir="auto"><img src="/assets/uploads/files/1720439828751-6e971ed4-d102-434d-98e3-fd9d1de48374-image.png" alt="6e971ed4-d102-434d-98e3-fd9d1de48374-image.png" class=" img-fluid img-markdown" /><br />
You can do your job with this code without modifying the source codes itselfs.</p>
<pre><code class="language-js">/* 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 () =&gt; {
						const { resolve, promise } = Promise.withResolvers()
						const img = new Image()
						img.crossOrigin = 'Anonymous'
						img.src = 'https://corsproxy.io/?' + url
						img.onload = () =&gt; {
							const colorThief = new ColorThief()
							const color = colorThief.getColor(img)
							resolve(color)
						}
						return promise
					}
					if (typeof ColorThief === 'undefined') {
						const loadScript = async (src) =&gt; {
							const { resolve, promise } = Promise.withResolvers()
							const script = document.createElement('script')
							script.src = src
							document.head.appendChild(script)
							script.onload = () =&gt; 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
				},
			},
		],
	},
},
</code></pre>
]]></description><link>https://forum.magicmirror.builders/post/118777</link><guid isPermaLink="true">https://forum.magicmirror.builders/post/118777</guid><dc:creator><![CDATA[MMRIZE]]></dc:creator><pubDate>Mon, 08 Jul 2024 11:57:48 GMT</pubDate></item><item><title><![CDATA[Reply to Dynamic Font Colors on Sun, 07 Jul 2024 14:40:42 GMT]]></title><description><![CDATA[<p dir="auto"><a class="plugin-mentions-user plugin-mentions-a" href="/user/ijoshea" aria-label="Profile: ijoshea">@<bdi>ijoshea</bdi></a><br />
I had the same needs on building modules. (btw, GooglePhotos and CX3 were built by me :D )</p>
<p dir="auto">Sometimes I suggested other module’s background for the readability. Sometimes, I made an auto-calculated contrast color(e.g. CX3)</p>
<p dir="auto">My final conclusion is… waiting for new CSS feature <code>contrast-color()</code>. It will be introduced later this year in the most modern browsers.<br />
<a href="https://drafts.csswg.org/css-color-5/#contrast-color" target="_blank" rel="noopener noreferrer nofollow ugc">https://drafts.csswg.org/css-color-5/#contrast-color</a></p>
]]></description><link>https://forum.magicmirror.builders/post/118763</link><guid isPermaLink="true">https://forum.magicmirror.builders/post/118763</guid><dc:creator><![CDATA[MMRIZE]]></dc:creator><pubDate>Sun, 07 Jul 2024 14:40:42 GMT</pubDate></item><item><title><![CDATA[Reply to Dynamic Font Colors on Sun, 07 Jul 2024 13:31:51 GMT]]></title><description><![CDATA[<p dir="auto"><a class="plugin-mentions-user plugin-mentions-a" href="/user/ijoshea" aria-label="Profile: ijoshea">@<bdi>ijoshea</bdi></a> I added the scripts to MMM-ImagesPhotos (getScripts response)<br />
and they are loaded… BUT the document on(‘load’)  from the script above doesn’t fire…<br />
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<br />
(css cover and contain both adjust the aspect ratio)</p>
]]></description><link>https://forum.magicmirror.builders/post/118759</link><guid isPermaLink="true">https://forum.magicmirror.builders/post/118759</guid><dc:creator><![CDATA[sdetweil]]></dc:creator><pubDate>Sun, 07 Jul 2024 13:31:51 GMT</pubDate></item><item><title><![CDATA[Reply to Dynamic Font Colors on Sun, 07 Jul 2024 13:16:35 GMT]]></title><description><![CDATA[<p dir="auto"><a class="plugin-mentions-user plugin-mentions-a" href="/user/mmrize" aria-label="Profile: MMRIZE">@<bdi>MMRIZE</bdi></a> AND it doesn’t work…</p>
]]></description><link>https://forum.magicmirror.builders/post/118758</link><guid isPermaLink="true">https://forum.magicmirror.builders/post/118758</guid><dc:creator><![CDATA[sdetweil]]></dc:creator><pubDate>Sun, 07 Jul 2024 13:16:35 GMT</pubDate></item><item><title><![CDATA[Reply to Dynamic Font Colors on Sun, 07 Jul 2024 12:59:54 GMT]]></title><description><![CDATA[<p dir="auto"><a class="plugin-mentions-user plugin-mentions-a" href="/user/ijoshea" aria-label="Profile: ijoshea">@<bdi>ijoshea</bdi></a><br />
It seems weird to import JS in css.</p>
]]></description><link>https://forum.magicmirror.builders/post/118754</link><guid isPermaLink="true">https://forum.magicmirror.builders/post/118754</guid><dc:creator><![CDATA[MMRIZE]]></dc:creator><pubDate>Sun, 07 Jul 2024 12:59:54 GMT</pubDate></item><item><title><![CDATA[Reply to Dynamic Font Colors on Sun, 07 Jul 2024 11:00:18 GMT]]></title><description><![CDATA[<p dir="auto"><a class="plugin-mentions-user plugin-mentions-a" href="/user/ijoshea" aria-label="Profile: ijoshea">@<bdi>ijoshea</bdi></a> id like this too. if you ope  the developers window  you should see your script loaded and be able to debug it<br />
I think you might need the full url</p>
<pre><code class="language-text">http://localhost:mm_port/modules....
</code></pre>
]]></description><link>https://forum.magicmirror.builders/post/118751</link><guid isPermaLink="true">https://forum.magicmirror.builders/post/118751</guid><dc:creator><![CDATA[sdetweil]]></dc:creator><pubDate>Sun, 07 Jul 2024 11:00:18 GMT</pubDate></item></channel></rss>