From b10838c5ba7a460c172d7f36c6d2f70f90d6ba11 Mon Sep 17 00:00:00 2001 From: Yohan Boniface Date: Mon, 30 Oct 2023 18:14:41 +0100 Subject: [PATCH] Automagically change svg icon color according to background color --- umap/static/umap/js/umap.core.js | 22 +++++++++---------- umap/static/umap/js/umap.features.js | 2 ++ umap/static/umap/js/umap.icon.js | 32 +++++++++++++++++----------- 3 files changed, 32 insertions(+), 24 deletions(-) diff --git a/umap/static/umap/js/umap.core.js b/umap/static/umap/js/umap.core.js index 5958598b..cf62745e 100644 --- a/umap/static/umap/js/umap.core.js +++ b/umap/static/umap/js/umap.core.js @@ -363,21 +363,21 @@ L.DomUtil.after = (target, el) => { } L.DomUtil.RGBRegex = /rgb *\( *([0-9]{1,3}) *, *([0-9]{1,3}) *, *([0-9]{1,3}) *\)/ - L.DomUtil.TextColorFromBackgroundColor = (el) => { - let out = '#000000' - if (!window.getComputedStyle) { - return out - } + return L.DomUtil.contrastedColor(el) ? '#ffffff' : '#000000' +} +const _CACHE_CONSTRAST = {} +L.DomUtil.contrastedColor = (el, bgcolor) => { + // Return 0 for black and 1 for white + // bgcolor is a human color, it can be a any keyword (purpleā€¦) + if (typeof _CACHE_CONSTRAST[bgcolor] !== 'undefined') return _CACHE_CONSTRAST[bgcolor] + let out = 0 let rgb = window.getComputedStyle(el).getPropertyValue('background-color') rgb = L.DomUtil.RGBRegex.exec(rgb) - if (!rgb || rgb.length !== 4) { - return out - } + if (!rgb || rgb.length !== 4) return out rgb = parseInt(rgb[1], 10) + parseInt(rgb[2], 10) + parseInt(rgb[3], 10) - if (rgb < (255 * 3) / 2) { - out = '#ffffff' - } + if (rgb < (255 * 3) / 2) out = 1 + if (bgcolor) _CACHE_CONSTRAST[bgcolor] = out return out } L.DomEvent.once = (el, types, fn, context) => { diff --git a/umap/static/umap/js/umap.features.js b/umap/static/umap/js/umap.features.js index 91df595d..f72467db 100644 --- a/umap/static/umap/js/umap.features.js +++ b/umap/static/umap/js/umap.features.js @@ -608,6 +608,8 @@ L.U.Marker = L.Marker.extend({ _initIcon: function () { this.options.icon = this.getIcon() L.Marker.prototype._initIcon.call(this) + // Allow to run code when icon is actually part of the DOM + this.options.icon.onAdd() this.resetTooltip() }, diff --git a/umap/static/umap/js/umap.icon.js b/umap/static/umap/js/umap.icon.js index a77de8f0..a9591501 100644 --- a/umap/static/umap/js/umap.icon.js +++ b/umap/static/umap/js/umap.icon.js @@ -38,6 +38,8 @@ L.U.Icon = L.DivIcon.extend({ formatUrl: function (url, feature) { return L.Util.greedyTemplate(url || '', feature ? feature.extendedProperties() : {}) }, + + onAdd: function () {}, }) L.U.Icon.Default = L.U.Icon.extend({ @@ -63,6 +65,19 @@ L.U.Icon.Default = L.U.Icon.extend({ this.elements.arrow.style.opacity = opacity }, + onAdd: function () { + const src = this._getIconUrl('icon') + // Decide whether to switch svg to white or not, but do it + // only for internal SVG, as invert could do weird things + if (src.startsWith('/') && src.endsWith('.svg')) { + const bgcolor = this._getColor() + // Must be called after icon container is added to the DOM + if (L.DomUtil.contrastedColor(this.elements.container, bgcolor)) { + this.elements.img.style.filter = 'invert(1)' + } + } + }, + createIcon: function () { this.elements = {} this.elements.main = L.DomUtil.create('div') @@ -76,9 +91,9 @@ L.U.Icon.Default = L.U.Icon.extend({ if (src) { // An url. if ( - src.indexOf('http') === 0 || - src.indexOf('/') === 0 || - src.indexOf('data:image') === 0 + src.startsWith('http') || + src.startsWith('/') || + src.startsWith('data:image') ) { this.elements.img = L.DomUtil.create('img', null, this.elements.container) this.elements.img.src = src @@ -165,7 +180,6 @@ L.U.Icon.Ball = L.U.Icon.Default.extend({ }, }) -const _CACHE_COLOR = {} L.U.Icon.Cluster = L.DivIcon.extend({ options: { iconSize: [40, 40], @@ -192,14 +206,6 @@ L.U.Icon.Cluster = L.DivIcon.extend({ if (this.datalayer.options.cluster && this.datalayer.options.cluster.textColor) { color = this.datalayer.options.cluster.textColor } - if (!color) { - if (typeof _CACHE_COLOR[backgroundColor] === 'undefined') { - color = L.DomUtil.TextColorFromBackgroundColor(el) - _CACHE_COLOR[backgroundColor] = color - } else { - color = _CACHE_COLOR[backgroundColor] - } - } - return color + return color || L.DomUtil.TextColorFromBackgroundColor(el, backgroundColor) }, })