mirror of
https://github.com/umap-project/umap.git
synced 2025-04-29 03:42:37 +02:00
feat: display an image from Panoramax in OSM template when tag is defined (#2338)
 I initially just wanted to work on that simple Panoramax feature, but faced a bunch of bugs! - one bad var remaining since whatever refactor (and no tests for this popup template!) - title was duplicated, since whatever refactor (and not tests for this…) - title text was in black on blue background
This commit is contained in:
commit
7f3726ddd1
3 changed files with 93 additions and 17 deletions
|
@ -152,6 +152,19 @@ class GeoRSSLink extends PopupTemplate {
|
||||||
}
|
}
|
||||||
|
|
||||||
class OSM extends TitleMixin(PopupTemplate) {
|
class OSM extends TitleMixin(PopupTemplate) {
|
||||||
|
renderTitle(feature) {
|
||||||
|
const title = DomUtil.add('h3', 'popup-title')
|
||||||
|
const color = feature.getPreviewColor()
|
||||||
|
title.style.backgroundColor = color
|
||||||
|
const iconUrl = feature.getDynamicOption('iconUrl')
|
||||||
|
const icon = Icon.makeElement(iconUrl, title)
|
||||||
|
DomUtil.addClass(icon, 'icon')
|
||||||
|
Icon.setContrast(icon, title, iconUrl, color)
|
||||||
|
if (DomUtil.contrastedColor(title, color)) title.style.color = 'white'
|
||||||
|
DomUtil.add('span', '', title, this.getName(feature))
|
||||||
|
return title
|
||||||
|
}
|
||||||
|
|
||||||
getName(feature) {
|
getName(feature) {
|
||||||
const props = feature.properties
|
const props = feature.properties
|
||||||
const locale = getLocale()
|
const locale = getLocale()
|
||||||
|
@ -162,15 +175,6 @@ class OSM extends TitleMixin(PopupTemplate) {
|
||||||
renderBody(feature) {
|
renderBody(feature) {
|
||||||
const props = feature.properties
|
const props = feature.properties
|
||||||
const body = document.createElement('div')
|
const body = document.createElement('div')
|
||||||
const title = DomUtil.add('h3', 'popup-title', container)
|
|
||||||
const color = feature.getPreviewColor()
|
|
||||||
title.style.backgroundColor = color
|
|
||||||
const iconUrl = feature.getDynamicOption('iconUrl')
|
|
||||||
const icon = Icon.makeElement(iconUrl, title)
|
|
||||||
DomUtil.addClass(icon, 'icon')
|
|
||||||
Icon.setContrast(icon, title, iconUrl, color)
|
|
||||||
if (DomUtil.contrastedColor(title, color)) title.style.color = 'white'
|
|
||||||
DomUtil.add('span', '', title, this.getName(feature))
|
|
||||||
const street = props['addr:street']
|
const street = props['addr:street']
|
||||||
if (street) {
|
if (street) {
|
||||||
const row = DomUtil.add('address', 'address', body)
|
const row = DomUtil.add('address', 'address', body)
|
||||||
|
@ -207,6 +211,13 @@ class OSM extends TitleMixin(PopupTemplate) {
|
||||||
Utils.loadTemplate(`<div><a href="mailto:${email}">${email}</a></div>`)
|
Utils.loadTemplate(`<div><a href="mailto:${email}">${email}</a></div>`)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
if (props.panoramax) {
|
||||||
|
body.appendChild(
|
||||||
|
Utils.loadTemplate(
|
||||||
|
`<div><img src="https://api.panoramax.xyz/api/pictures/${props.panoramax}/sd.jpg" /></div>`
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
const id = props['@id'] || props.id
|
const id = props['@id'] || props.id
|
||||||
if (id) {
|
if (id) {
|
||||||
body.appendChild(
|
body.appendChild(
|
||||||
|
|
|
@ -170,22 +170,43 @@ L.DomUtil.contrastWCAG21 = (rgb) => {
|
||||||
const contrast = (whiteLum + 0.05) / (lum + 0.05)
|
const contrast = (whiteLum + 0.05) / (lum + 0.05)
|
||||||
return contrast > 3 ? 1 : 0
|
return contrast > 3 ? 1 : 0
|
||||||
}
|
}
|
||||||
|
L.DomUtil.colorNameToHex = (str) => {
|
||||||
|
const ctx = document.createElement('canvas').getContext('2d')
|
||||||
|
ctx.fillStyle = str
|
||||||
|
return ctx.fillStyle
|
||||||
|
}
|
||||||
|
L.DomUtil.hexToRGB = (hex) => {
|
||||||
|
return hex
|
||||||
|
.replace(
|
||||||
|
/^#?([a-f\d])([a-f\d])([a-f\d])$/i,
|
||||||
|
(m, r, g, b) => `#${r}${r}${g}${g}${b}${b}`
|
||||||
|
)
|
||||||
|
.substring(1)
|
||||||
|
.match(/.{2}/g)
|
||||||
|
.map((x) => Number.parseInt(x, 16))
|
||||||
|
}
|
||||||
|
|
||||||
const _CACHE_CONSTRAST = {}
|
const _CACHE_CONSTRAST = {}
|
||||||
L.DomUtil.contrastedColor = (el, bgcolor) => {
|
L.DomUtil.contrastedColor = (el, bgcolor) => {
|
||||||
// Return 0 for black and 1 for white
|
// Return 0 for black and 1 for white
|
||||||
// bgcolor is a human color, it can be a any keyword (purple…)
|
// bgcolor is a human color, it can be a any keyword (purple…)
|
||||||
if (typeof _CACHE_CONSTRAST[bgcolor] !== 'undefined') return _CACHE_CONSTRAST[bgcolor]
|
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) return out
|
if (rgb && rgb.length === 4) {
|
||||||
rgb = [
|
rgb = [
|
||||||
Number.parseInt(rgb[1], 10),
|
Number.parseInt(rgb[1], 10),
|
||||||
Number.parseInt(rgb[2], 10),
|
Number.parseInt(rgb[2], 10),
|
||||||
Number.parseInt(rgb[3], 10),
|
Number.parseInt(rgb[3], 10),
|
||||||
]
|
]
|
||||||
out = L.DomUtil.contrastWCAG21(rgb)
|
} else {
|
||||||
|
// The element may not yet be added to the DOM, so let's try
|
||||||
|
// another way
|
||||||
|
const hex = L.DomUtil.colorNameToHex(bgcolor)
|
||||||
|
rgb = L.DomUtil.hexToRGB(hex)
|
||||||
|
}
|
||||||
|
if (!rgb) return 1
|
||||||
|
const out = L.DomUtil.contrastWCAG21(rgb)
|
||||||
if (bgcolor) _CACHE_CONSTRAST[bgcolor] = out
|
if (bgcolor) _CACHE_CONSTRAST[bgcolor] = out
|
||||||
return out
|
return out
|
||||||
}
|
}
|
||||||
|
|
44
umap/tests/integration/test_popup.py
Normal file
44
umap/tests/integration/test_popup.py
Normal file
|
@ -0,0 +1,44 @@
|
||||||
|
import pytest
|
||||||
|
from playwright.sync_api import expect
|
||||||
|
|
||||||
|
from ..base import DataLayerFactory
|
||||||
|
|
||||||
|
pytestmark = pytest.mark.django_db
|
||||||
|
|
||||||
|
OSM_DATA = {
|
||||||
|
"type": "FeatureCollection",
|
||||||
|
"features": [
|
||||||
|
{
|
||||||
|
"type": "Feature",
|
||||||
|
"geometry": {"type": "Point", "coordinates": [2.49, 48.79]},
|
||||||
|
"properties": {
|
||||||
|
"amenity": "restaurant",
|
||||||
|
"cuisine": "italian",
|
||||||
|
"name": "A Casa di Nonna",
|
||||||
|
"panoramax": "d811b398-d930-4cf8-95a2-0c29c34d9fca",
|
||||||
|
"phone": "+33 1 48 89 54 12",
|
||||||
|
"takeaway:covid19": "yes",
|
||||||
|
"wheelchair": "no",
|
||||||
|
"id": "node/1130849864",
|
||||||
|
},
|
||||||
|
"id": "AzMjk",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
"_umap_options": {
|
||||||
|
"popupTemplate": "OSM",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def test_openstreetmap_popup(live_server, map, page):
|
||||||
|
DataLayerFactory(map=map, data=OSM_DATA)
|
||||||
|
page.goto(f"{live_server.url}{map.get_absolute_url()}#18/48.79/2.49")
|
||||||
|
expect(page.locator(".umap-icon-active")).to_be_hidden()
|
||||||
|
page.locator(".leaflet-marker-icon").click()
|
||||||
|
expect(page.get_by_role("heading", name="A Casa di Nonna")).to_be_visible()
|
||||||
|
expect(page.get_by_text("+33 1 48 89 54 12")).to_be_visible()
|
||||||
|
img = page.locator(".umap-popup-content img")
|
||||||
|
expect(img).to_have_attribute(
|
||||||
|
"src",
|
||||||
|
"https://api.panoramax.xyz/api/pictures/d811b398-d930-4cf8-95a2-0c29c34d9fca/sd.jpg",
|
||||||
|
)
|
Loading…
Reference in a new issue