feat: add unified index, map layers, and ITS asset management views and symbology

This commit is contained in:
Karl Determe 2026-10-08 16:45:33 +02:00
parent 7d5718dec2
commit 80c54a083d
5 changed files with 164 additions and 25 deletions

View file

@ -427,6 +427,33 @@
glyphCodepoint: 'f82b', glyphCodepoint: 'f82b',
mapImage: 'icon-sign', mapImage: 'icon-sign',
}, },
// ITS
itsgeoasset: {
thematic: 'its',
color: '#0288d1',
iconUrl: null,
iconClass: 'bi-broadcast-pin',
glyphCodepoint: 'f1d5',
mapImage: 'icon-its',
},
itsbollardsystem: {
thematic: 'its',
color: '#0288d1',
iconUrl: null,
iconClass: 'bi-border-width',
glyphCodepoint: 'f1ca',
mapImage: 'icon-itsbollardsystem',
},
itsbollardplot: {
thematic: 'its',
color: '#0288d1',
iconUrl: '/static/assets/its_bollard_plot_icon.svg?v=20261008',
iconSize: 42,
iconClass: 'bi-cone-striped',
glyphCodepoint: 'f2aa',
mapImage: 'icon-itsbollardplot',
},
}; };
// ─── 3. Specific Parking Spot Overrides by spot_type ───────────────────────── // ─── 3. Specific Parking Spot Overrides by spot_type ─────────────────────────
@ -633,6 +660,7 @@
natureplanter: injected.natureplanter || (ASSET_TYPE_OVERRIDES.natureplanter && ASSET_TYPE_OVERRIDES.natureplanter.iconUrl), natureplanter: injected.natureplanter || (ASSET_TYPE_OVERRIDES.natureplanter && ASSET_TYPE_OVERRIDES.natureplanter.iconUrl),
artworkfountain: injected.artworkfountain || ASSET_TYPE_OVERRIDES.artworkfountain.iconUrl, artworkfountain: injected.artworkfountain || ASSET_TYPE_OVERRIDES.artworkfountain.iconUrl,
artworkmonument: injected.artworkmonument || ASSET_TYPE_OVERRIDES.artworkmonument.iconUrl, artworkmonument: injected.artworkmonument || ASSET_TYPE_OVERRIDES.artworkmonument.iconUrl,
itsbollardplot: injected.itsbollardplot || (ASSET_TYPE_OVERRIDES.itsbollardplot && ASSET_TYPE_OVERRIDES.itsbollardplot.iconUrl),
}; };
return urls; return urls;
} }
@ -656,6 +684,9 @@
{ name: 'icon-roaddrain', codepoint: 'f617', color: '#1e88e5' }, { name: 'icon-roaddrain', codepoint: 'f617', color: '#1e88e5' },
{ name: 'icon-structures', codepoint: 'f876', color: '#6d4c41' }, { name: 'icon-structures', codepoint: 'f876', color: '#6d4c41' },
{ name: 'icon-its', codepoint: 'f1d5', color: '#0288d1' }, { name: 'icon-its', codepoint: 'f1d5', color: '#0288d1' },
{ name: 'icon-itsgeoasset', codepoint: 'f1d5', color: '#0288d1' },
{ name: 'icon-itsbollardsystem', codepoint: 'f1ca', color: '#0288d1' },
{ name: 'icon-itsbollardplot', codepoint: 'f2aa', color: '#0288d1' },
{ name: 'icon-clean', codepoint: 'f78a', color: '#5e5e5e' }, { name: 'icon-clean', codepoint: 'f78a', color: '#5e5e5e' },
{ name: 'icon-cleanglasscontainer', codepoint: 'f78a', color: '#16a34a' }, { name: 'icon-cleanglasscontainer', codepoint: 'f78a', color: '#16a34a' },
{ name: 'icon-artworks', codepoint: 'f4b0', color: '#f24141' }, { name: 'icon-artworks', codepoint: 'f4b0', color: '#f24141' },
@ -749,6 +780,9 @@
['==', ['get', 'asset_type'], 'roadfurniture'], 'icon-speedbump', ['==', ['get', 'asset_type'], 'roadfurniture'], 'icon-speedbump',
['==', ['get', 'asset_type'], 'roadconcreteblockset'], 'icon-roadconcreteblockset', ['==', ['get', 'asset_type'], 'roadconcreteblockset'], 'icon-roadconcreteblockset',
['==', ['get', 'asset_type'], 'naturerwiasset'], 'icon-naturerwiasset', ['==', ['get', 'asset_type'], 'naturerwiasset'], 'icon-naturerwiasset',
['==', ['get', 'asset_type'], 'itsbollardplot'], 'icon-itsbollardplot',
['==', ['get', 'asset_type'], 'itsbollardsystem'], 'icon-itsbollardsystem',
['==', ['get', 'asset_type'], 'itsgeoasset'], 'icon-its',
['==', ['get', 'spot_type'], 'scooter_drop_zone'], 'icon-parkingspot-scooter_drop_zone', ['==', ['get', 'spot_type'], 'scooter_drop_zone'], 'icon-parkingspot-scooter_drop_zone',
['==', ['get', 'spot_type'], 'pmr'], 'icon-parkingspot-pmr', ['==', ['get', 'spot_type'], 'pmr'], 'icon-parkingspot-pmr',
['==', ['get', 'spot_type'], 'ev_charging'], 'icon-parkingspot-ev_charging', ['==', ['get', 'spot_type'], 'ev_charging'], 'icon-parkingspot-ev_charging',
@ -924,14 +958,20 @@
'#0288d1' '#0288d1'
], ],
['==', ['get', 'thematic'], 'nature'], '#2e7d32', ['==', ['get', 'thematic'], 'nature'], '#2e7d32',
['==', ['get', 'asset_type'], 'itsbollardsystem'], '#0288d1',
['match', ['get', 'asset_type'], 'roadway', '#334155', 'sidewalk', '#64748b', getThematicColorExpr()] ['match', ['get', 'asset_type'], 'roadway', '#334155', 'sidewalk', '#64748b', getThematicColorExpr()]
], ],
'line-width': [ 'line-width': [
'case', 'case',
['any', ['boolean', ['feature-state', 'highlighted'], false], ['boolean', ['feature-state', 'selected'], false]], 6, ['any', ['boolean', ['feature-state', 'highlighted'], false], ['boolean', ['feature-state', 'selected'], false]], 6,
['==', ['get', 'asset_type'], 'itsbollardsystem'], 5,
3.5 3.5
], ],
'line-opacity': 0.88, 'line-opacity': [
'case',
['==', ['get', 'asset_type'], 'itsbollardsystem'], 0.95,
0.88
],
}, },
minzoom: 8, minzoom: 8,
}; };

View file

@ -0,0 +1,36 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64" width="64" height="64" aria-hidden="true">
<ellipse cx="32" cy="54" rx="22" ry="5" fill="#1e293b" opacity="0.3"/>
<ellipse cx="32" cy="52" rx="18" ry="4" fill="#334155"/>
<ellipse cx="32" cy="51" rx="16" ry="3.5" fill="#64748b"/>
<ellipse cx="32" cy="50.5" rx="13" ry="2.8" fill="#1e293b"/>
<defs>
<linearGradient id="bollardGrad" x1="0%" y1="0%" x2="100%" y2="0%">
<stop offset="0%" stop-color="#0284c7"/>
<stop offset="25%" stop-color="#38bdf8"/>
<stop offset="60%" stop-color="#0284c7"/>
<stop offset="100%" stop-color="#0369a1"/>
</linearGradient>
<linearGradient id="capGrad" x1="0%" y1="0%" x2="0%" y2="100%">
<stop offset="0%" stop-color="#7dd3fc"/>
<stop offset="100%" stop-color="#0284c7"/>
</linearGradient>
<linearGradient id="bandGrad" x1="0%" y1="0%" x2="100%" y2="0%">
<stop offset="0%" stop-color="#f59e0b"/>
<stop offset="35%" stop-color="#fef08a"/>
<stop offset="70%" stop-color="#f59e0b"/>
<stop offset="100%" stop-color="#d97706"/>
</linearGradient>
</defs>
<path d="M 21,24 L 21,50 C 21,53 43,53 43,50 L 43,24 Z" fill="url(#bollardGrad)"/>
<path d="M 21,21 L 21,27 C 21,29.5 43,29.5 43,27 L 43,21 C 43,23.5 21,23.5 21,21 Z" fill="url(#bandGrad)"/>
<path d="M 21,15 L 21,21 C 21,23.5 43,23.5 43,21 L 43,15 Z" fill="url(#bollardGrad)"/>
<ellipse cx="32" cy="15" rx="11" ry="3.5" fill="url(#capGrad)" stroke="#bae6fd" stroke-width="0.8"/>
<ellipse cx="32" cy="14.2" rx="7" ry="2" fill="#ffffff" opacity="0.6"/>
<circle cx="26" cy="24.5" r="1" fill="#ffffff"/>
<circle cx="32" cy="25.2" r="1.1" fill="#ffffff"/>
<circle cx="38" cy="24.5" r="1" fill="#ffffff"/>
</svg>

After

Width:  |  Height:  |  Size: 1.7 KiB

View file

@ -535,7 +535,7 @@ function buildColumns() {
} }
}, },
{ {
field: 'element_type', title: gettext('Type'), sortable: true, width: 130, widthUnit: 'px', valign: 'middle', field: 'element_type', title: gettext('Type'), sortable: true, width: 145, widthUnit: 'px', valign: 'middle',
formatter: function (v, row) { formatter: function (v, row) {
const table = $('#unified-table'); const table = $('#unified-table');
let isCatVisible = false; let isCatVisible = false;
@ -543,10 +543,21 @@ function buildColumns() {
isCatVisible = table.length && typeof table.bootstrapTable === 'function' && isCatVisible = table.length && typeof table.bootstrapTable === 'function' &&
table.bootstrapTable('getVisibleColumns').some(c => c.field === 'category'); table.bootstrapTable('getVisibleColumns').some(c => c.field === 'category');
} catch (e) {} } catch (e) {}
if (!isCatVisible && row && row.is_location && row.category) {
return `${escapeHtml(v || '-')} <span class="badge bg-light text-secondary border fw-normal ms-1" style="font-size:0.75rem;">${escapeHtml(row.category)}</span>`; let iconPrefix = '';
if (typeof AssetSymbology !== 'undefined' && row && !row.is_location && !row.is_management_zone) {
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;`,
imgClass: 'me-1'
});
} }
return escapeHtml(v || '-');
if (!isCatVisible && row && row.is_location && row.category) {
return `${iconPrefix}${escapeHtml(v || '-')} <span class="badge bg-light text-secondary border fw-normal ms-1" style="font-size:0.75rem;">${escapeHtml(row.category)}</span>`;
}
return `${iconPrefix}${escapeHtml(v || '-')}`;
} }
}, },
{ field: 'thematic_name', title: gettext('Thématique'), sortable: true, width: 140, widthUnit: 'px', valign: 'middle' }, { field: 'thematic_name', title: gettext('Thématique'), sortable: true, width: 140, widthUnit: 'px', valign: 'middle' },
@ -2016,6 +2027,7 @@ function collectClickedAssets(clickEvent) {
element_type: p.element_type || '', element_type: p.element_type || '',
detail_url: p.detail_url || null, detail_url: p.detail_url || null,
feature_id: id, feature_id: id,
extra_info: p.plots_count != null ? `${p.plots_count} plot(s)` : (p.bollard_type || ''),
}); });
}); });
@ -2149,15 +2161,26 @@ function showAssetClickPopup(clickEvent) {
const type = escapeHtml(a.element_type || a.asset_type || ''); const type = escapeHtml(a.element_type || a.asset_type || '');
const thematic = escapeHtml(a.thematic_name || a.thematic || ''); const thematic = escapeHtml(a.thematic_name || a.thematic || '');
const name = escapeHtml(a.name || ''); const name = escapeHtml(a.name || '');
const extra = a.extra_info ? ` &bull; <span class="badge bg-light text-primary border" style="font-size:0.7rem;">${escapeHtml(a.extra_info)}</span>` : '';
const detailAnchor = a.detail_url const detailAnchor = a.detail_url
? `<a href="${escapeHtml(a.detail_url)}">${code}</a>` ? `<a href="${escapeHtml(a.detail_url)}">${code}</a>`
: `<span>${code}</span>`; : `<span>${code}</span>`;
let iconPrefix = '';
if (typeof AssetSymbology !== 'undefined') {
const symb = AssetSymbology.getAssetSymbology(a);
const colorStyle = symb.color ? `color:${symb.color};` : '';
iconPrefix = AssetSymbology.renderIconHtml(symb, {
style: `${colorStyle} font-size: 1rem; vertical-align: -1px; margin-right: 5px;`,
imgClass: 'me-1'
});
}
return ` return `
<div class="asset-popup-item" style="display:flex; gap:0.5rem; align-items:flex-start; justify-content:space-between; padding:0.25rem 0; border-bottom:1px solid #f1f3f5;"> <div class="asset-popup-item" style="display:flex; gap:0.5rem; align-items:flex-start; justify-content:space-between; padding:0.25rem 0; border-bottom:1px solid #f1f3f5;">
<div style="min-width:0;"> <div style="min-width:0;">
<div style="font-weight:600; line-height:1.1;">${detailAnchor}</div> <div style="font-weight:600; line-height:1.1;">${iconPrefix}${detailAnchor}</div>
<div style="font-size:0.75rem; color:#6c757d; line-height:1.2;">${type}${thematic ? ' - ' + thematic : ''}</div> <div style="font-size:0.75rem; color:#6c757d; line-height:1.2;">${type}${thematic ? ' - ' + thematic : ''}${extra}</div>
${name ? `<div style="font-size:0.75rem; color:#495057; line-height:1.2;">${name}</div>` : ''} ${name ? `<div style="font-size:0.75rem; color:#495057; line-height:1.2;">${name}</div>` : ''}
</div> </div>
<button type="button" <button type="button"

View file

@ -201,6 +201,12 @@ function loadUnifiedMapIcons(map) {
.then(data => { if (!map.hasImage('icon-artworkmonument')) map.addImage('icon-artworkmonument', data); }) .then(data => { if (!map.hasImage('icon-artworkmonument')) map.addImage('icon-artworkmonument', data); })
.catch(e => console.warn('unified_map_layers: could not load artworkmonument icon', e)); .catch(e => console.warn('unified_map_layers: could not load artworkmonument icon', e));
} }
// itsbollardplot: dedicated automatic bollard / plot SVG (42 px)
if (iconUrls.itsbollardplot && !map.hasImage('icon-itsbollardplot')) {
loadNormalisedIcon(iconUrls.itsbollardplot, 42)
.then(data => { if (!map.hasImage('icon-itsbollardplot')) map.addImage('icon-itsbollardplot', data); })
.catch(e => console.warn('unified_map_layers: could not load itsbollardplot icon', e));
}
// If the SVG above is unavailable, publiclighting falls back to Bootstrap glyph. // If the SVG above is unavailable, publiclighting falls back to Bootstrap glyph.
// ── Bootstrap Icons glyph SDF icons (recoloured by icon-color) ────────── // ── Bootstrap Icons glyph SDF icons (recoloured by icon-color) ──────────
@ -634,6 +640,7 @@ const _unified_assets_symbol = {
['==', ['get', 'asset_type'], 'publiclightingelectricalcabinet'], ['==', ['get', 'asset_type'], 'publiclightingelectricalcabinet'],
['==', ['get', 'trafficlightelectricalcabinet'], 'trafficlightelectricalcabinet'], ['==', ['get', 'trafficlightelectricalcabinet'], 'trafficlightelectricalcabinet'],
['==', ['get', 'asset_type'], 'naturerwiasset'], ['==', ['get', 'asset_type'], 'naturerwiasset'],
['==', ['get', 'asset_type'], 'itsbollardplot'],
['==', ['get', 'category'], 'Avaloir'], ['==', ['get', 'category'], 'Avaloir'],
['==', ['get', 'category'], 'Corbeille de rue'], ['==', ['get', 'category'], 'Corbeille de rue'],
['==', ['get', 'category'], 'Corbeille'], ['==', ['get', 'category'], 'Corbeille'],
@ -669,6 +676,7 @@ const _unified_assets_symbol = {
['==', ['get', 'asset_type'], 'publiclightingelectricalcabinet'], ['==', ['get', 'asset_type'], 'publiclightingelectricalcabinet'],
['==', ['get', 'trafficlightelectricalcabinet'], 'trafficlightelectricalcabinet'], ['==', ['get', 'trafficlightelectricalcabinet'], 'trafficlightelectricalcabinet'],
['==', ['get', 'asset_type'], 'naturerwiasset'], ['==', ['get', 'asset_type'], 'naturerwiasset'],
['==', ['get', 'asset_type'], 'itsbollardplot'],
['==', ['get', 'category'], 'Avaloir'], ['==', ['get', 'category'], 'Avaloir'],
['==', ['get', 'category'], 'Corbeille de rue'], ['==', ['get', 'category'], 'Corbeille de rue'],
['==', ['get', 'category'], 'Corbeille'], ['==', ['get', 'category'], 'Corbeille'],
@ -704,6 +712,7 @@ const _unified_assets_symbol = {
['==', ['get', 'asset_type'], 'publiclightingelectricalcabinet'], ['==', ['get', 'asset_type'], 'publiclightingelectricalcabinet'],
['==', ['get', 'asset_type'], 'trafficlightelectricalcabinet'], ['==', ['get', 'asset_type'], 'trafficlightelectricalcabinet'],
['==', ['get', 'asset_type'], 'naturerwiasset'], ['==', ['get', 'asset_type'], 'naturerwiasset'],
['==', ['get', 'asset_type'], 'itsbollardplot'],
['==', ['get', 'category'], 'Avaloir'], ['==', ['get', 'category'], 'Avaloir'],
['==', ['get', 'category'], 'Corbeille de rue'], ['==', ['get', 'category'], 'Corbeille de rue'],
['==', ['get', 'category'], 'Corbeille'], ['==', ['get', 'category'], 'Corbeille'],
@ -739,6 +748,7 @@ const _unified_assets_symbol = {
['==', ['get', 'asset_type'], 'publiclightingelectricalcabinet'], ['==', ['get', 'asset_type'], 'publiclightingelectricalcabinet'],
['==', ['get', 'asset_type'], 'trafficlightelectricalcabinet'], ['==', ['get', 'asset_type'], 'trafficlightelectricalcabinet'],
['==', ['get', 'asset_type'], 'naturerwiasset'], ['==', ['get', 'asset_type'], 'naturerwiasset'],
['==', ['get', 'asset_type'], 'itsbollardplot'],
['==', ['get', 'category'], 'Avaloir'], ['==', ['get', 'category'], 'Avaloir'],
['==', ['get', 'category'], 'Corbeille de rue'], ['==', ['get', 'category'], 'Corbeille de rue'],
['==', ['get', 'category'], 'Corbeille'], ['==', ['get', 'category'], 'Corbeille'],
@ -774,6 +784,7 @@ const _unified_assets_symbol = {
['==', ['get', 'asset_type'], 'publiclightingelectricalcabinet'], ['==', ['get', 'asset_type'], 'publiclightingelectricalcabinet'],
['==', ['get', 'asset_type'], 'trafficlightelectricalcabinet'], ['==', ['get', 'asset_type'], 'trafficlightelectricalcabinet'],
['==', ['get', 'asset_type'], 'naturerwiasset'], ['==', ['get', 'asset_type'], 'naturerwiasset'],
['==', ['get', 'asset_type'], 'itsbollardplot'],
['==', ['get', 'category'], 'Avaloir'], ['==', ['get', 'category'], 'Avaloir'],
['==', ['get', 'category'], 'Corbeille de rue'], ['==', ['get', 'category'], 'Corbeille de rue'],
['==', ['get', 'category'], 'Corbeille'], ['==', ['get', 'category'], 'Corbeille'],
@ -809,6 +820,7 @@ const _unified_assets_symbol = {
['==', ['get', 'asset_type'], 'publiclightingelectricalcabinet'], ['==', ['get', 'asset_type'], 'publiclightingelectricalcabinet'],
['==', ['get', 'asset_type'], 'trafficlightelectricalcabinet'], ['==', ['get', 'asset_type'], 'trafficlightelectricalcabinet'],
['==', ['get', 'asset_type'], 'naturerwiasset'], ['==', ['get', 'asset_type'], 'naturerwiasset'],
['==', ['get', 'asset_type'], 'itsbollardplot'],
['==', ['get', 'category'], 'Avaloir'], ['==', ['get', 'category'], 'Avaloir'],
['==', ['get', 'category'], 'Corbeille de rue'], ['==', ['get', 'category'], 'Corbeille de rue'],
['==', ['get', 'category'], 'Corbeille'], ['==', ['get', 'category'], 'Corbeille'],
@ -844,6 +856,7 @@ const _unified_assets_symbol = {
['==', ['get', 'asset_type'], 'publiclightingelectricalcabinet'], ['==', ['get', 'asset_type'], 'publiclightingelectricalcabinet'],
['==', ['get', 'asset_type'], 'trafficlightelectricalcabinet'], ['==', ['get', 'asset_type'], 'trafficlightelectricalcabinet'],
['==', ['get', 'asset_type'], 'naturerwiasset'], ['==', ['get', 'asset_type'], 'naturerwiasset'],
['==', ['get', 'asset_type'], 'itsbollardplot'],
['==', ['get', 'category'], 'Avaloir'], ['==', ['get', 'category'], 'Avaloir'],
['==', ['get', 'category'], 'Corbeille de rue'], ['==', ['get', 'category'], 'Corbeille de rue'],
['==', ['get', 'category'], 'Corbeille'], ['==', ['get', 'category'], 'Corbeille'],
@ -876,6 +889,7 @@ const _unified_assets_symbol = {
['==', ['get', 'thematic'], 'publiclighting'], 'bottom', ['==', ['get', 'thematic'], 'publiclighting'], 'bottom',
['==', ['get', 'thematic'], 'trafficlights'], 'bottom', ['==', ['get', 'thematic'], 'trafficlights'], 'bottom',
['==', ['get', 'thematic'], 'nature'], 'bottom', ['==', ['get', 'thematic'], 'nature'], 'bottom',
['==', ['get', 'asset_type'], 'itsbollardplot'], 'bottom',
'center' 'center'
], ],
'icon-offset': [ 'icon-offset': [
@ -912,6 +926,8 @@ const _unified_assets_symbol = {
['all', ['==', ['get', 'thematic'], 'roads'], ['match', ['geometry-type'], ['Polygon', 'MultiPolygon', 'LineString', 'MultiLineString'], true, false]], 0, ['all', ['==', ['get', 'thematic'], 'roads'], ['match', ['geometry-type'], ['Polygon', 'MultiPolygon', 'LineString', 'MultiLineString'], true, false]], 0,
['all', ['==', ['get', 'asset_type'], 'naturerwiasset'], ['match', ['geometry-type'], ['Polygon', 'MultiPolygon', 'LineString', 'MultiLineString'], true, false]], 0, ['all', ['==', ['get', 'asset_type'], 'naturerwiasset'], ['match', ['geometry-type'], ['Polygon', 'MultiPolygon', 'LineString', 'MultiLineString'], true, false]], 0,
['==', ['get', 'asset_type'], 'naturegreensurface'], 0, ['==', ['get', 'asset_type'], 'naturegreensurface'], 0,
['==', ['get', 'asset_type'], 'itsbollardsystem'], 0,
['match', ['geometry-type'], ['LineString', 'MultiLineString'], true, false], 0,
['boolean', ['feature-state', 'highlighted'], false], 1, ['boolean', ['feature-state', 'highlighted'], false], 1,
0.85 0.85
], ],
@ -1084,14 +1100,20 @@ const _unified_assets_line = (typeof AssetSymbology !== 'undefined' && AssetSymb
'line-color': [ 'line-color': [
'case', 'case',
['==', ['get', 'thematic'], 'nature'], '#2e7d32', ['==', ['get', 'thematic'], 'nature'], '#2e7d32',
['==', ['get', 'asset_type'], 'itsbollardsystem'], '#0288d1',
THEMATIC_COLOR_EXPR THEMATIC_COLOR_EXPR
], ],
'line-width': [ 'line-width': [
'case', 'case',
['boolean', ['feature-state', 'highlighted'], false], 5, ['boolean', ['feature-state', 'highlighted'], false], 6,
['==', ['get', 'asset_type'], 'itsbollardsystem'], 5,
3 3
], ],
'line-opacity': 0.8, 'line-opacity': [
'case',
['==', ['get', 'asset_type'], 'itsbollardsystem'], 0.95,
0.8
],
}, },
minzoom: 8, minzoom: 8,
}; };

View file

@ -10,7 +10,7 @@ from django.contrib.gis.db.models.functions import Transform
from django.contrib.gis.geos import GEOSGeometry, Point from django.contrib.gis.geos import GEOSGeometry, Point
from django.contrib.gis.db.models.functions import Distance from django.contrib.gis.db.models.functions import Distance
from django.contrib.contenttypes.models import ContentType from django.contrib.contenttypes.models import ContentType
from django.db.models import Q, Case, When, IntegerField, CharField from django.db.models import Q, Case, When, IntegerField, CharField, Count
from django.db.models.functions import Lower from django.db.models.functions import Lower
from django.db.models import Func, Prefetch from django.db.models import Func, Prefetch
from django.db import connection from django.db import connection
@ -324,15 +324,13 @@ def its_assets_geojson(request):
def obj_to_feature(obj, asset_type=None): def obj_to_feature(obj, asset_type=None):
geometry, lon, lat = build_geometry_and_coords(obj) geometry, lon, lat = build_geometry_and_coords(obj)
return { props = {
"type": "Feature",
"id": obj.id,
"geometry": geometry,
"properties": {
"code": obj.code, "code": obj.code,
"name": obj.get_name(), "name": obj.get_name(),
"category": obj.category.get_name() if obj.category else None, "category": obj.category.get_name() if obj.category else None,
"category_id": obj.category_id,
"model": obj.model.get_name() if obj.model else None, "model": obj.model.get_name() if obj.model else None,
"model_id": obj.model_id,
"status": obj.status, "status": obj.status,
"validation_status": obj.validation_status, "validation_status": obj.validation_status,
"lon": lon, "lon": lon,
@ -342,7 +340,26 @@ def its_assets_geojson(request):
"element_type": get_element_type_label(asset_type or ''), "element_type": get_element_type_label(asset_type or ''),
"thematic": "its", "thematic": "its",
"is_location": False, "is_location": False,
}, }
if asset_type == "itsbollardsystem":
props["width"] = obj.width
props["direction"] = obj.get_direction_display() if hasattr(obj, 'get_direction_display') else obj.direction
props["plots_count"] = getattr(obj, 'plots_total', None)
if props["plots_count"] is None and hasattr(obj, 'plots'):
props["plots_count"] = obj.plots.count()
if obj.geom:
props["length"] = round(obj.geom.length, 2)
elif asset_type == "itsbollardplot":
props["position"] = obj.position
props["bollard_type"] = obj.get_bollard_type_display() if hasattr(obj, 'get_bollard_type_display') else obj.bollard_type
if getattr(obj, 'system', None):
props["system_code"] = obj.system.code
props["system_name"] = obj.system.name
return {
"type": "Feature",
"id": obj.id,
"geometry": geometry,
"properties": props,
} }
def add_assets_to_features(queryset, asset_type, features, feature_count): def add_assets_to_features(queryset, asset_type, features, feature_count):
@ -362,6 +379,7 @@ def its_assets_geojson(request):
bollard_system_qs = ( bollard_system_qs = (
ITSBollardSystem.objects ITSBollardSystem.objects
.select_related('location', 'category', 'model') .select_related('location', 'category', 'model')
.annotate(plots_total=Count('plots'))
.all() .all()
) )
bollard_plot_qs = ( bollard_plot_qs = (