Merge pull request #1387 from umap-project/svg-pictogram
Allow to upload SVG pictograms and change hue according to background color
This commit is contained in:
commit
4643930870
5 changed files with 50 additions and 25 deletions
17
umap/migrations/0015_alter_pictogram_pictogram.py
Normal file
17
umap/migrations/0015_alter_pictogram_pictogram.py
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
# Generated by Django 4.2.2 on 2023-10-30 11:27
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
dependencies = [
|
||||||
|
("umap", "0014_map_created_at"),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name="pictogram",
|
||||||
|
name="pictogram",
|
||||||
|
field=models.FileField(upload_to="pictogram"),
|
||||||
|
),
|
||||||
|
]
|
|
@ -284,7 +284,7 @@ class Pictogram(NamedModel):
|
||||||
"""
|
"""
|
||||||
|
|
||||||
attribution = models.CharField(max_length=300)
|
attribution = models.CharField(max_length=300)
|
||||||
pictogram = models.ImageField(upload_to="pictogram")
|
pictogram = models.FileField(upload_to="pictogram")
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def json(self):
|
def json(self):
|
||||||
|
|
|
@ -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.RGBRegex = /rgb *\( *([0-9]{1,3}) *, *([0-9]{1,3}) *, *([0-9]{1,3}) *\)/
|
||||||
|
|
||||||
L.DomUtil.TextColorFromBackgroundColor = (el) => {
|
L.DomUtil.TextColorFromBackgroundColor = (el) => {
|
||||||
let out = '#000000'
|
return L.DomUtil.contrastedColor(el) ? '#ffffff' : '#000000'
|
||||||
if (!window.getComputedStyle) {
|
}
|
||||||
return out
|
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')
|
let rgb = window.getComputedStyle(el).getPropertyValue('background-color')
|
||||||
rgb = L.DomUtil.RGBRegex.exec(rgb)
|
rgb = L.DomUtil.RGBRegex.exec(rgb)
|
||||||
if (!rgb || rgb.length !== 4) {
|
if (!rgb || rgb.length !== 4) return out
|
||||||
return out
|
|
||||||
}
|
|
||||||
rgb = parseInt(rgb[1], 10) + parseInt(rgb[2], 10) + parseInt(rgb[3], 10)
|
rgb = parseInt(rgb[1], 10) + parseInt(rgb[2], 10) + parseInt(rgb[3], 10)
|
||||||
if (rgb < (255 * 3) / 2) {
|
if (rgb < (255 * 3) / 2) out = 1
|
||||||
out = '#ffffff'
|
if (bgcolor) _CACHE_CONSTRAST[bgcolor] = out
|
||||||
}
|
|
||||||
return out
|
return out
|
||||||
}
|
}
|
||||||
L.DomEvent.once = (el, types, fn, context) => {
|
L.DomEvent.once = (el, types, fn, context) => {
|
||||||
|
|
|
@ -608,6 +608,8 @@ L.U.Marker = L.Marker.extend({
|
||||||
_initIcon: function () {
|
_initIcon: function () {
|
||||||
this.options.icon = this.getIcon()
|
this.options.icon = this.getIcon()
|
||||||
L.Marker.prototype._initIcon.call(this)
|
L.Marker.prototype._initIcon.call(this)
|
||||||
|
// Allow to run code when icon is actually part of the DOM
|
||||||
|
this.options.icon.onAdd()
|
||||||
this.resetTooltip()
|
this.resetTooltip()
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
|
@ -38,6 +38,8 @@ L.U.Icon = L.DivIcon.extend({
|
||||||
formatUrl: function (url, feature) {
|
formatUrl: function (url, feature) {
|
||||||
return L.Util.greedyTemplate(url || '', feature ? feature.extendedProperties() : {})
|
return L.Util.greedyTemplate(url || '', feature ? feature.extendedProperties() : {})
|
||||||
},
|
},
|
||||||
|
|
||||||
|
onAdd: function () {},
|
||||||
})
|
})
|
||||||
|
|
||||||
L.U.Icon.Default = L.U.Icon.extend({
|
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
|
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 () {
|
createIcon: function () {
|
||||||
this.elements = {}
|
this.elements = {}
|
||||||
this.elements.main = L.DomUtil.create('div')
|
this.elements.main = L.DomUtil.create('div')
|
||||||
|
@ -76,9 +91,9 @@ L.U.Icon.Default = L.U.Icon.extend({
|
||||||
if (src) {
|
if (src) {
|
||||||
// An url.
|
// An url.
|
||||||
if (
|
if (
|
||||||
src.indexOf('http') === 0 ||
|
src.startsWith('http') ||
|
||||||
src.indexOf('/') === 0 ||
|
src.startsWith('/') ||
|
||||||
src.indexOf('data:image') === 0
|
src.startsWith('data:image')
|
||||||
) {
|
) {
|
||||||
this.elements.img = L.DomUtil.create('img', null, this.elements.container)
|
this.elements.img = L.DomUtil.create('img', null, this.elements.container)
|
||||||
this.elements.img.src = src
|
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({
|
L.U.Icon.Cluster = L.DivIcon.extend({
|
||||||
options: {
|
options: {
|
||||||
iconSize: [40, 40],
|
iconSize: [40, 40],
|
||||||
|
@ -192,14 +206,6 @@ L.U.Icon.Cluster = L.DivIcon.extend({
|
||||||
if (this.datalayer.options.cluster && this.datalayer.options.cluster.textColor) {
|
if (this.datalayer.options.cluster && this.datalayer.options.cluster.textColor) {
|
||||||
color = this.datalayer.options.cluster.textColor
|
color = this.datalayer.options.cluster.textColor
|
||||||
}
|
}
|
||||||
if (!color) {
|
return color || L.DomUtil.TextColorFromBackgroundColor(el, backgroundColor)
|
||||||
if (typeof _CACHE_COLOR[backgroundColor] === 'undefined') {
|
|
||||||
color = L.DomUtil.TextColorFromBackgroundColor(el)
|
|
||||||
_CACHE_COLOR[backgroundColor] = color
|
|
||||||
} else {
|
|
||||||
color = _CACHE_COLOR[backgroundColor]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return color
|
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
Loading…
Reference in a new issue