Skip to content

Commit

Permalink
feat: display an image from Panoramax in OSM template when tag is def…
Browse files Browse the repository at this point in the history
…ined (#2338)

![Screenshot From 2024-12-05
11-45-05](https://github.com/user-attachments/assets/97949b2f-4716-4d56-bb2e-ce481b932dcb)

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
  • Loading branch information
yohanboniface authored Dec 5, 2024
2 parents 2c601e4 + 82853f7 commit 7f3726d
Show file tree
Hide file tree
Showing 3 changed files with 93 additions and 17 deletions.
29 changes: 20 additions & 9 deletions umap/static/umap/js/modules/rendering/template.js
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,19 @@ class GeoRSSLink extends 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) {
const props = feature.properties
const locale = getLocale()
Expand All @@ -162,15 +175,6 @@ class OSM extends TitleMixin(PopupTemplate) {
renderBody(feature) {
const props = feature.properties
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']
if (street) {
const row = DomUtil.add('address', 'address', body)
Expand Down Expand Up @@ -207,6 +211,13 @@ class OSM extends TitleMixin(PopupTemplate) {
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
if (id) {
body.appendChild(
Expand Down
37 changes: 29 additions & 8 deletions umap/static/umap/js/umap.core.js
Original file line number Diff line number Diff line change
Expand Up @@ -170,22 +170,43 @@ L.DomUtil.contrastWCAG21 = (rgb) => {
const contrast = (whiteLum + 0.05) / (lum + 0.05)
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 = {}
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
rgb = [
Number.parseInt(rgb[1], 10),
Number.parseInt(rgb[2], 10),
Number.parseInt(rgb[3], 10),
]
out = L.DomUtil.contrastWCAG21(rgb)
if (rgb && rgb.length === 4) {
rgb = [
Number.parseInt(rgb[1], 10),
Number.parseInt(rgb[2], 10),
Number.parseInt(rgb[3], 10),
]
} 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
return out
}
Expand Down
44 changes: 44 additions & 0 deletions umap/tests/integration/test_popup.py
Original file line number Diff line number Diff line change
@@ -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",
)

0 comments on commit 7f3726d

Please sign in to comment.