206 lines
No EOL
6.6 KiB
JavaScript
206 lines
No EOL
6.6 KiB
JavaScript
|
||
const map = new maplibregl.Map({
|
||
container: "map",
|
||
style: window.MAP_STYLE_LIGHT,
|
||
//style: 'https://tiles.openfreemap.org/styles/positron',
|
||
center: [4.3572, 50.8477],
|
||
zoom: 11,
|
||
minzoom: 0,
|
||
maxzoom: 24
|
||
});
|
||
|
||
async function fetchAndMergeGeoJSON(urls) {
|
||
const allFeatures = [];
|
||
|
||
for (const url of urls) {
|
||
const response = await fetch(url);
|
||
const data = await response.json();
|
||
if (data && data.features) {
|
||
allFeatures.push(...data.features);
|
||
}
|
||
}
|
||
|
||
return {
|
||
type: 'FeatureCollection',
|
||
features: allFeatures
|
||
};
|
||
}
|
||
|
||
|
||
map.on('load', async () => {
|
||
const mergedGeoJSON = await fetchAndMergeGeoJSON(interventions_geojson_urls);
|
||
|
||
map.addSource('interventions', {
|
||
'type': 'geojson',
|
||
'data': mergedGeoJSON
|
||
});
|
||
|
||
// map.addLayer({
|
||
// id: 'heatmap',
|
||
// type: 'heatmap',
|
||
// source: 'interventions',
|
||
// paint: {
|
||
// 'heatmap-weight': ['get', 'density'],
|
||
// 'heatmap-intensity': 1,
|
||
// 'heatmap-color': [
|
||
// 'interpolate',
|
||
// ['linear'],
|
||
// ['heatmap-density'],
|
||
// 0, 'rgba(33,102,172,0)',
|
||
// 0.2, 'rgb(103,169,207)',
|
||
// 0.4, 'rgb(209,229,240)',
|
||
// 0.6, 'rgb(253,219,199)',
|
||
// 0.8, 'rgb(239,138,98)',
|
||
// 1, 'rgb(178,24,43)'
|
||
// ],
|
||
// 'heatmap-radius': 15,
|
||
// 'heatmap-opacity': 0.75
|
||
// }
|
||
// });
|
||
|
||
map.addLayer({
|
||
'id': 'interventions',
|
||
'type': 'circle',
|
||
'source': 'interventions',
|
||
//filter: ['has', 'point_count'],
|
||
minzoom: 0,
|
||
maxzoom: 24,
|
||
'paint': {
|
||
'circle-radius': [
|
||
'interpolate',
|
||
['linear'],
|
||
['zoom'],
|
||
10, 5,
|
||
22, 15
|
||
],
|
||
//'circle-color': '#0094ff',
|
||
'circle-color': INTERVENTION_STATUS_COLOR_EXPR,
|
||
'circle-opacity': 0.7
|
||
}
|
||
});
|
||
|
||
});
|
||
|
||
function statusFormatter(value) {
|
||
const icons = {
|
||
'in_preparation': { label: gettext('En préparation'), icon: 'bi-pencil', color: 'secondary' },
|
||
'to_be_approved': { label: gettext('À approuver'), icon: 'bi-hourglass-split', color: 'warning' },
|
||
'to_be_planned': { label: gettext('À planifier'), icon: 'bi-calendar-plus', color: 'warning' },
|
||
'to_be_processed': { label: gettext('À traiter'), icon: 'bi-tools', color: 'danger' },
|
||
'assigned': { label: gettext('Pris en charge'), icon: 'bi-person-check', color: 'warning' },
|
||
'in_progress': { label: gettext('Démarré'), icon: 'bi-play-circle', color: 'primary' },
|
||
'on_pause': { label: gettext('En pause'), icon: 'bi-pause-circle', color: 'warning' },
|
||
'finished': { label: gettext('Terminé'), icon: 'bi-check-circle', color: 'info' },
|
||
'processed': { label: gettext('Traité'), icon: 'bi-check2-all', color: 'info' },
|
||
'to_be_corrected': { label: gettext('À corriger'), icon: 'bi-exclamation-circle', color: 'danger' },
|
||
'corrected': { label: gettext('Corrigé'), icon: 'bi-check-circle', color: 'info' },
|
||
'validated': { label: gettext('Validé'), icon: 'bi-award', color: 'success' },
|
||
'invoiced': { label: gettext('Comptabilisé'), icon: 'bi-receipt', color: 'dark' },
|
||
'closed': { label: gettext('Finalisé'), icon: 'bi-archive', color: 'dark' },
|
||
// 'archived': { label: gettext('Archivé'), icon: 'bi-box-seam', color: 'dark' },
|
||
'canceled': { label: gettext('Annulé'), icon: 'bi-x-circle', color: 'secondary' },
|
||
};
|
||
|
||
const entry = icons[value];
|
||
if (!entry) return value;
|
||
|
||
return `<span class="badge text-bg-${entry.color} status-${value}"><i class="bi ${entry.icon} me-2"></i>${entry.label}</span>`;
|
||
}
|
||
|
||
map.on('click', function(e) {
|
||
const radiusInPixels = 10; // Rayon autour du clic
|
||
|
||
const features = map.queryRenderedFeatures([
|
||
[e.point.x - radiusInPixels, e.point.y - radiusInPixels],
|
||
[e.point.x + radiusInPixels, e.point.y + radiusInPixels]
|
||
], {
|
||
layers: ['interventions']
|
||
});
|
||
|
||
if (!features.length) {
|
||
return;
|
||
}
|
||
|
||
// Générer le contenu de la popup avec tous les points proches
|
||
const popupContent = features.map((feature) => {
|
||
const props = feature.properties;
|
||
return `
|
||
<div>
|
||
<strong><a href="${interventionDetailUrlPattern.replace('/0/', '/' + props.id + '/')}">${props.code || gettext('Intervention')}</a></strong><br/>
|
||
${gettext("Statut")}: ${statusFormatter(props.status)}<br/>
|
||
${gettext("Titre")}: ${props.title || '-'}
|
||
</div>
|
||
<hr/>
|
||
`;
|
||
}).join('');
|
||
|
||
// Afficher la popup à l’endroit du clic
|
||
new maplibregl.Popup()
|
||
.setLngLat(e.lngLat)
|
||
.setHTML(popupContent)
|
||
.addTo(map);
|
||
});
|
||
|
||
map.on('mouseenter', 'interventions', () => {
|
||
map.getCanvas().style.cursor = 'pointer';
|
||
});
|
||
map.on('mouseleave', 'interventions', () => {
|
||
map.getCanvas().style.cursor = '';
|
||
});
|
||
|
||
function populateLegend() {
|
||
const statuses = ['to_be_processed', 'assigned', 'in_progress', 'on_pause', 'finished'];
|
||
const legendContainer = document.getElementById('map-legend');
|
||
|
||
if (!legendContainer) return;
|
||
|
||
const legendItems = statuses.map(status => {
|
||
return `<div class="mb-1">${statusFormatter(status)}</div>`;
|
||
});
|
||
|
||
legendContainer.innerHTML = `
|
||
${legendItems.join('')}
|
||
`;
|
||
}
|
||
|
||
document.addEventListener('DOMContentLoaded', populateLegend);
|
||
|
||
// ### chart ###
|
||
|
||
const series = [
|
||
{
|
||
name: gettext('Correctif'),
|
||
type: 'line',
|
||
smooth: true,
|
||
data: seriesData['Correctif'],
|
||
itemStyle: { color: '#dc3545' } // Bootstrap "danger"
|
||
},
|
||
{
|
||
name: gettext('Préventif'),
|
||
type: 'line',
|
||
smooth: true,
|
||
data: seriesData['Préventif'],
|
||
itemStyle: { color: '#ffc107' } // Bootstrap "warning"
|
||
},
|
||
{
|
||
name: gettext('Amélioratif'),
|
||
type: 'line',
|
||
smooth: true,
|
||
data: seriesData['Amélioratif'],
|
||
itemStyle: { color: '#28a745' } // Bootstrap "success"
|
||
}
|
||
];
|
||
|
||
const option = {
|
||
legend: { data: ['Correctif', 'Préventif', 'Amélioratif'] },
|
||
tooltip: { trigger: 'axis' },
|
||
xAxis: { type: 'category', data: seriesData.dates },
|
||
yAxis: { type: 'value' },
|
||
series: series
|
||
};
|
||
|
||
const chartDom = document.getElementById('chartNbrInterventions');
|
||
const myChart = echarts.init(chartDom);
|
||
myChart.setOption(option);
|
||
|
||
window.addEventListener('resize', () => myChart.resize()); |