From 587f4abf8ab1bca60698b463a30d4c63097a6cf8 Mon Sep 17 00:00:00 2001 From: kdeterme Date: Fri, 9 Oct 2026 13:32:09 +0200 Subject: [PATCH] =?UTF-8?q?feat(nature):=20distinction=20arbres=20r=C3=A9g?= =?UTF-8?q?ionaux,=20filtre=20gestionnaire,=20tableau=20compact=20et=20ess?= =?UTF-8?q?ences=20botaniques?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- loko/assets/static/assets/asset_symbology.js | 48 ++++++++++++++++++- .../assets/nature_tree_icon_regional.svg | 20 ++++++++ .../assets/nature_tree_icon_remarkable.svg | 20 ++++++++ loko/assets/static/assets/unified_index.js | 15 +++++- .../static/assets/unified_map_layers.js | 10 ++++ .../templates/assets/unified_index.html | 20 ++++++-- loko/assets/views/core.py | 9 ++++ 7 files changed, 135 insertions(+), 7 deletions(-) create mode 100644 loko/assets/static/assets/nature_tree_icon_regional.svg create mode 100644 loko/assets/static/assets/nature_tree_icon_remarkable.svg diff --git a/loko/assets/static/assets/asset_symbology.js b/loko/assets/static/assets/asset_symbology.js index 949baa3..b83a761 100644 --- a/loko/assets/static/assets/asset_symbology.js +++ b/loko/assets/static/assets/asset_symbology.js @@ -261,6 +261,24 @@ glyphCodepoint: 'f30b', mapImage: 'icon-naturerwiasset', }, + naturetree_regional: { + thematic: 'nature', + color: '#1d4ed8', + iconUrl: '/static/assets/nature_tree_icon_regional.svg?v=20261009a', + iconSize: 56, + iconClass: 'bi-tree-fill', + glyphCodepoint: 'f5e1', + mapImage: 'icon-nature-regional', + }, + naturetree_remarkable: { + thematic: 'nature', + color: '#d97706', + iconUrl: '/static/assets/nature_tree_icon_remarkable.svg?v=20261009a', + iconSize: 56, + iconClass: 'bi-tree-fill', + glyphCodepoint: 'f5e1', + mapImage: 'icon-nature-remarkable', + }, naturetree: { thematic: 'nature', color: '#2e7d32', @@ -578,6 +596,20 @@ } // 3. Specific asset_type override + if (assetType === 'naturetree' || (thematic === 'nature' && (assetType === 'naturetree' || !assetType))) { + const isRemarkable = item.is_remarkable === true || item.is_remarkable === 'true'; + const isRegional = item.management_type === 'regional' || + (typeof item.managing_authority === 'string' && (item.managing_authority.toLowerCase().includes('région') || item.managing_authority.toLowerCase().includes('mobilité'))); + if (isRemarkable && ASSET_TYPE_OVERRIDES.naturetree_remarkable) { + return Object.assign({}, ASSET_TYPE_OVERRIDES.naturetree_remarkable); + } + if (isRegional && ASSET_TYPE_OVERRIDES.naturetree_regional) { + return Object.assign({}, ASSET_TYPE_OVERRIDES.naturetree_regional); + } + if (ASSET_TYPE_OVERRIDES.naturetree) { + return Object.assign({}, ASSET_TYPE_OVERRIDES.naturetree); + } + } if (assetType === 'naturebench') { const isPlanter = (item.asset_sub_type === 'planter') || ['Bac à fleurs / Jardinière', 'Bloembak', 'Jardinière', 'Bac à fleurs', 'Bac à plantes'].includes(item.model) || @@ -625,12 +657,17 @@ const customStyle = options.style ? ` style="${options.style}"` : ''; + const classList = ['asset-symbology-icon-img']; + if (options.imgClass) classList.push(options.imgClass); + const imgClass = classList.join(' '); + const defaultImgStyle = 'width: 20px; height: 20px; max-width: 20px; max-height: 20px; object-fit: contain; vertical-align: middle; display: inline-block;'; + const finalStyle = options.style ? ` style="${defaultImgStyle} ${options.style}"` : ` style="${defaultImgStyle}"`; + if (symbology.iconUrl) { - const imgClass = options.imgClass || 'asset-symbology-icon-img'; const fallbackUrl = symbology.fallbackUrl || (symbology.iconUrl.includes('.svg') ? symbology.iconUrl.replace(/\.svg(\?.*)?$/, '.png$1') : ''); const fallbackClass = options.iconClass || symbology.iconClass || 'bi-sign-stop-fill'; const onerrorAttr = ` onerror="this.onerror=null; ${fallbackUrl ? `if(this.src && this.src.indexOf('.svg') !== -1){ this.src='${fallbackUrl}'; } else {` : ''} this.style.display='none'; if(this.nextElementSibling){ this.nextElementSibling.style.display=''; } ${fallbackUrl ? '}' : ''}"`; - return ``; + return ``; } const iconClass = options.iconClass || symbology.iconClass || 'bi-pin-map'; @@ -653,6 +690,8 @@ publiclighting: injected.publiclighting || THEMATIC_CONFIG.publiclighting.iconUrl, publiclightingelectricalcabinet: injected.publiclightingelectricalcabinet || ASSET_TYPE_OVERRIDES.publiclightingelectricalcabinet.iconUrl, nature: injected.nature || THEMATIC_CONFIG.nature.iconUrl, + natureregional: injected.natureregional || (ASSET_TYPE_OVERRIDES.naturetree_regional && ASSET_TYPE_OVERRIDES.naturetree_regional.iconUrl), + natureremarkable: injected.natureremarkable || (ASSET_TYPE_OVERRIDES.naturetree_remarkable && ASSET_TYPE_OVERRIDES.naturetree_remarkable.iconUrl), structures: injected.structures || THEMATIC_CONFIG.structures.iconUrl, roaddrain: injected.roaddrain || ASSET_TYPE_OVERRIDES.roaddrain.iconUrl, roadconcreteblockset: injected.roadconcreteblockset || ASSET_TYPE_OVERRIDES.roadconcreteblockset.iconUrl, @@ -773,6 +812,11 @@ ['==', ['slice', ['get', 'code'], 0, 7], 'CSE-BAC'], ], 'icon-natureplanter', ['==', ['get', 'asset_type'], 'naturebench'], 'icon-naturebench', + ['all', ['==', ['get', 'thematic'], 'nature'], ['==', ['get', 'is_remarkable'], true]], 'icon-nature-remarkable', + ['all', ['==', ['get', 'thematic'], 'nature'], ['==', ['get', 'management_type'], 'regional']], 'icon-nature-regional', + ['all', ['==', ['get', 'asset_type'], 'naturetree'], ['==', ['get', 'is_remarkable'], true]], 'icon-nature-remarkable', + ['all', ['==', ['get', 'asset_type'], 'naturetree'], ['==', ['get', 'management_type'], 'regional']], 'icon-nature-regional', + ['==', ['get', 'asset_type'], 'naturetree'], 'icon-nature', ['==', ['get', 'asset_type'], 'drain'], 'icon-roaddrain', ['==', ['get', 'asset_type'], 'roaddrain'], 'icon-roaddrain', ['==', ['get', 'category'], 'Ralentisseur'], 'icon-speedbump', diff --git a/loko/assets/static/assets/nature_tree_icon_regional.svg b/loko/assets/static/assets/nature_tree_icon_regional.svg new file mode 100644 index 0000000..547ddaf --- /dev/null +++ b/loko/assets/static/assets/nature_tree_icon_regional.svg @@ -0,0 +1,20 @@ + diff --git a/loko/assets/static/assets/nature_tree_icon_remarkable.svg b/loko/assets/static/assets/nature_tree_icon_remarkable.svg new file mode 100644 index 0000000..00258b2 --- /dev/null +++ b/loko/assets/static/assets/nature_tree_icon_remarkable.svg @@ -0,0 +1,20 @@ + diff --git a/loko/assets/static/assets/unified_index.js b/loko/assets/static/assets/unified_index.js index 4331729..c2b8ade 100644 --- a/loko/assets/static/assets/unified_index.js +++ b/loko/assets/static/assets/unified_index.js @@ -549,7 +549,7 @@ function buildColumns() { const symb = AssetSymbology.getAssetSymbology(row); const colorStyle = symb.color ? `color:${symb.color};` : ''; iconPrefix = AssetSymbology.renderIconHtml(symb, { - style: `${colorStyle} font-size: 0.95rem; vertical-align: -1px; margin-right: 5px;`, + style: `${colorStyle} width: 20px; height: 20px; vertical-align: middle; margin-right: 6px;`, imgClass: 'me-1' }); } @@ -1593,6 +1593,11 @@ function buildAssetsGeojsonPostBody(thematicCode, bbox, includeNonGeoFilters) { } } if (thematicCode === 'nature') { + if (Array.isArray(thematicFilters.management_type) && thematicFilters.management_type.length) { + payload.management_type = thematicFilters.management_type; + } else if (thematicFilters.management_type) { + payload.management_type = [thematicFilters.management_type]; + } if (thematicFilters.location_type) { payload.location_type = thematicFilters.location_type; } @@ -2028,6 +2033,9 @@ function collectClickedAssets(clickEvent) { detail_url: p.detail_url || null, feature_id: id, extra_info: p.plots_count != null ? `${p.plots_count} plot(s)` : (p.bollard_type || ''), + management_type: p.management_type || '', + managing_authority: p.managing_authority || '', + is_remarkable: p.is_remarkable || false, }); }); @@ -2729,6 +2737,11 @@ function loadTableData(features) { model: p.model || '', status: p.status || '', detail_url: p.detail_url || null, + management_type: p.management_type || '', + managing_authority: p.managing_authority || '', + is_remarkable: p.is_remarkable || false, + scientific_name: p.scientific_name || '', + vernacular_name: p.vernacular_name || '', lon: p.lon, lat: p.lat, length: Number.isFinite(length) ? length : 0, diff --git a/loko/assets/static/assets/unified_map_layers.js b/loko/assets/static/assets/unified_map_layers.js index 7fdcd79..36beb22 100644 --- a/loko/assets/static/assets/unified_map_layers.js +++ b/loko/assets/static/assets/unified_map_layers.js @@ -140,6 +140,16 @@ function loadUnifiedMapIcons(map) { .then(data => { if (!map.hasImage('icon-nature')) map.addImage('icon-nature', data); }) .catch(e => console.warn('unified_map_layers: could not load nature icon', e)); } + if (iconUrls.natureregional && !map.hasImage('icon-nature-regional')) { + loadNormalisedIcon(iconUrls.natureregional, 56) + .then(data => { if (!map.hasImage('icon-nature-regional')) map.addImage('icon-nature-regional', data); }) + .catch(e => console.warn('unified_map_layers: could not load nature regional icon', e)); + } + if (iconUrls.natureremarkable && !map.hasImage('icon-nature-remarkable')) { + loadNormalisedIcon(iconUrls.natureremarkable, 56) + .then(data => { if (!map.hasImage('icon-nature-remarkable')) map.addImage('icon-nature-remarkable', data); }) + .catch(e => console.warn('unified_map_layers: could not load nature remarkable icon', e)); + } // structures: dedicated bridge/tunnel SVG (52 px) if (iconUrls.structures && !map.hasImage('icon-structures')) { diff --git a/loko/assets/templates/assets/unified_index.html b/loko/assets/templates/assets/unified_index.html index d661480..c8a5be6 100644 --- a/loko/assets/templates/assets/unified_index.html +++ b/loko/assets/templates/assets/unified_index.html @@ -480,7 +480,7 @@ text-transform: uppercase !important; letter-spacing: 0.04em !important; border-bottom: 1.5px solid #e2e8f0 !important; - padding: 0.65rem 0.75rem !important; + padding: 0.45rem 0.65rem !important; vertical-align: middle !important; white-space: nowrap !important; } @@ -489,16 +489,28 @@ padding: 0 !important; font-size: 0.74rem !important; font-weight: 600 !important; - line-height: 1.4 !important; + line-height: 1.3 !important; } /* Rows & Cells */ .bootstrap-table.bootstrap5 #unified-table td { - padding: 0.65rem 0.75rem !important; + padding: 0.32rem 0.65rem !important; vertical-align: middle !important; - font-size: 0.83rem !important; + font-size: 0.82rem !important; color: #334155; border-bottom: 1px solid #f1f5f9 !important; + line-height: 1.3 !important; + } + + .asset-symbology-icon-img { + width: 20px !important; + height: 20px !important; + max-width: 20px !important; + max-height: 20px !important; + object-fit: contain !important; + vertical-align: middle !important; + display: inline-block !important; + margin-right: 6px !important; } .bootstrap-table.bootstrap5 #unified-table tbody tr { diff --git a/loko/assets/views/core.py b/loko/assets/views/core.py index 2afb4e5..bb12877 100644 --- a/loko/assets/views/core.py +++ b/loko/assets/views/core.py @@ -753,6 +753,15 @@ def build_conditional_filter_config(accessible_thematics, user=None): # Nature if 'nature' in accessible_codes: config['nature'] = [ + { + 'key': 'management_type', + 'label': _('Gestionnaire'), + 'type': 'multi', + 'options': [ + {'value': 'municipal', 'label': _('Commune (Watermael-Boitsfort)')}, + {'value': 'regional', 'label': _('Région (Bruxelles Mobilité)')}, + ], + }, { 'key': 'location_type', 'label': _('Type de localisation'),