542 lines
No EOL
20 KiB
JavaScript
542 lines
No EOL
20 KiB
JavaScript
|
|
var tl_data = [];
|
|
|
|
var intersections_geojson = {};
|
|
const intersectionsgeojsonloader = new GeojsonLoader();
|
|
const intersections_layer_def = {
|
|
'id': 'traffic-lights',
|
|
'type': 'circle',
|
|
'source': 'traffic-lights',
|
|
'filter': [
|
|
'all',
|
|
['!', ['coalesce', ['get', 'is_radar'], false]]
|
|
],
|
|
'paint': {
|
|
'circle-radius': [
|
|
'interpolate',
|
|
['linear'],
|
|
['zoom'],
|
|
10, 2,
|
|
13, 4,
|
|
16, 7,
|
|
19, 10
|
|
],
|
|
'circle-color': [
|
|
'case',
|
|
['boolean', ['feature-state', 'highlighted'], false], '#ffeb3bbf', // Highlight color
|
|
'#0094ff' // Default color
|
|
],
|
|
'circle-opacity': 0.7
|
|
}
|
|
};
|
|
|
|
const intersections_radar_outline_layer_def = {
|
|
'id': 'traffic-lights-radar-outline',
|
|
'type': 'symbol',
|
|
'source': 'traffic-lights',
|
|
'filter': ['coalesce', ['get', 'is_radar'], false],
|
|
'layout': {
|
|
'icon-image': 'cross-sdf-border',
|
|
'icon-size': ['interpolate', ['linear'], ['zoom'], 10, 0.22, 13, 0.35, 16, 0.6, 19, 0.85],
|
|
'icon-allow-overlap': true,
|
|
'icon-ignore-placement': true,
|
|
},
|
|
'paint': {
|
|
'icon-color': [
|
|
'case',
|
|
['boolean', ['feature-state', 'highlighted'], false], '#ffeb3b',
|
|
'#ffffff'
|
|
]
|
|
}
|
|
};
|
|
|
|
const intersections_radar_layer_def = {
|
|
'id': 'traffic-lights-radar',
|
|
'type': 'symbol',
|
|
'source': 'traffic-lights',
|
|
'filter': ['coalesce', ['get', 'is_radar'], false],
|
|
'layout': {
|
|
'icon-image': 'cross-sdf',
|
|
'icon-size': ['interpolate', ['linear'], ['zoom'], 10, 0.22, 13, 0.35, 16, 0.6, 19, 0.85],
|
|
'icon-allow-overlap': true,
|
|
'icon-ignore-placement': true,
|
|
},
|
|
'paint': {
|
|
'icon-color': [
|
|
'case',
|
|
['boolean', ['feature-state', 'highlighted'], false], '#ffeb3bbf', // Highlight color
|
|
'#0094ff' // Default color
|
|
]
|
|
}
|
|
};
|
|
|
|
const intersections_layers = [intersections_layer_def, intersections_radar_outline_layer_def, intersections_radar_layer_def];
|
|
|
|
handleGeojsonMapLoading(init=true, intersectionsgeojsonloader, 'traffic-lights', intersections_layers);
|
|
|
|
// Reset table if error occurs when loading GeoJSON
|
|
intersectionsgeojsonloader.addEventListener("geojsonError", event => {
|
|
loadDataIntoIntersectionsTable([]);
|
|
});
|
|
|
|
// Load data into table when GeoJSON is loaded
|
|
intersectionsgeojsonloader.addEventListener("geojsonLoaded", event => {
|
|
var geojson_data = event.detail;
|
|
loadDataIntoIntersectionsTable(geojson_data.features);
|
|
intersections_geojson = geojson_data;
|
|
});
|
|
|
|
|
|
var assets_geojson = {};
|
|
const assetsgeojsonloader = new GeojsonLoader();
|
|
const assets_layer_def = {
|
|
'id': 'traffic-lights-assets',
|
|
'type': 'circle',
|
|
'source': 'traffic-lights-assets',
|
|
'paint': {
|
|
'circle-radius': [
|
|
'interpolate',
|
|
['linear'],
|
|
['zoom'],
|
|
13, 1,
|
|
22, 10
|
|
],
|
|
'circle-color': [
|
|
'case',
|
|
['boolean', ['feature-state', 'highlighted'], false], '#ffeb3bbf', // Highlight color
|
|
'#f24141' // Default color
|
|
],
|
|
'circle-opacity': 0.7
|
|
},
|
|
minzoom: 15
|
|
}
|
|
handleGeojsonMapLoading(init=true, assetsgeojsonloader, 'traffic-lights-assets', [assets_layer_def]);
|
|
|
|
assetsgeojsonloader.addEventListener("geojsonError", event => {
|
|
loadDataIntoAssetsTable([]);
|
|
});
|
|
|
|
assetsgeojsonloader.addEventListener("geojsonLoaded", event => {
|
|
var geojson_data = event.detail;
|
|
loadDataIntoAssetsTable(geojson_data.features);
|
|
assets_geojson = geojson_data;
|
|
});
|
|
|
|
|
|
|
|
// Load Map
|
|
maploader.loadMap("map");
|
|
|
|
// Map layers events
|
|
registerLayerMouseEnter(map, 'traffic-lights', popup, 'code', 13);
|
|
registerLayerMouseLeave(map, 'traffic-lights', popup);
|
|
registerLayerMouseEnter(map, 'traffic-lights-radar', popup, 'code', 13);
|
|
registerLayerMouseLeave(map, 'traffic-lights-radar', popup);
|
|
registerLayerMouseEnter(map, 'traffic-lights-assets', popup, 'name', 17);
|
|
registerLayerMouseLeave(map, 'traffic-lights-assets', popup);
|
|
|
|
var intersectionshighlightState = { previousId: null }; // Track the previously highlighted feature
|
|
const handleIntersectionClick = (e) => {
|
|
const featureId = e.features[0].id;
|
|
const currentZoom = map.getZoom();
|
|
if (currentZoom > 13) {
|
|
// Highlight the corresponding row in the Bootstrap table
|
|
highlightRow('#intersections-table', 'id', featureId);
|
|
|
|
// Update feature highlight on the map
|
|
highlightMapFeature(map, 'traffic-lights', featureId, intersectionshighlightState);
|
|
highlightMapFeature(map, 'traffic-lights-radar', featureId, intersectionshighlightState);
|
|
|
|
// Load assets GeoJSON for the selected intersection
|
|
const intersectionId = featureId;
|
|
const intersectionAssetsGeojsonUrl = `${assetsgeojsonUrl}?intersection=${intersectionId}`;
|
|
assetsgeojsonloader.loadGeojson(intersectionAssetsGeojsonUrl);
|
|
}
|
|
};
|
|
|
|
map.on('click', 'traffic-lights', handleIntersectionClick);
|
|
map.on('click', 'traffic-lights-radar', handleIntersectionClick);
|
|
|
|
var assetshighlightState = { previousId: null }; // Track the previously highlighted feature
|
|
map.on('click', 'traffic-lights-assets', (e) => {
|
|
const featureId = e.features[0].id;
|
|
const currentZoom = map.getZoom();
|
|
if (currentZoom > 13) {
|
|
//window.open(trafficlightintersectionsurl+e.features[0].id+"/","_self");
|
|
|
|
// Highlight the corresponding row in the Bootstrap table
|
|
highlightRow('#assets-table', 'id', featureId);
|
|
|
|
// Update feature highlight on the map
|
|
highlightMapFeature(map, 'traffic-lights-assets', featureId, assetshighlightState);
|
|
}
|
|
});
|
|
|
|
|
|
|
|
|
|
// Charger les données initiales
|
|
const params = new URLSearchParams(window.location.search).toString();
|
|
intersectionsgeojsonloader.loadGeojson(intersectionsgeojsonUrl+`?${params}`);
|
|
assetsgeojsonloader.loadGeojson(assetsgeojsonUrl);
|
|
|
|
|
|
|
|
function actionsFormatter(value, row, index) {
|
|
resp = `<button class="btn btn-sm btn-light detail-btn" data-id="${row.id}" data-bs-toggle="tooltip" title="Detail">
|
|
<i class="bi bi-info-circle"></i>
|
|
</button>`;
|
|
|
|
if (row.lon) {
|
|
resp = resp +
|
|
`<button class="btn btn-sm btn-light zoom-btn" data-lon="${row.lon}" data-lat="${row.lat}" data-bs-toggle="tooltip" title="Zoom">
|
|
<i class="bi bi-geo-alt"></i>
|
|
</button>`;
|
|
}
|
|
|
|
if (preventive_draft_id && preventive_draft_id !== "None") {
|
|
// If we are in the context of a preventive draft, we add the button to select the intersection
|
|
if (selected_intersections_set.has(row.id)) {
|
|
icon_select = 'bi-check-square-fill';
|
|
} else {
|
|
icon_select = 'bi-square';
|
|
}
|
|
resp = resp +
|
|
`<button class="btn btn-sm btn-light intersection-btn-toggle" data-id="${row.id}" data-bs-toggle="tooltip" title="Désélectionner l'intersection">
|
|
<i class="bi ${icon_select}"></i>
|
|
</button>`;
|
|
}
|
|
|
|
return resp;
|
|
}
|
|
|
|
function actionsFormatterAssets(value, row, index) {
|
|
resp = `<button class="btn btn-sm btn-light detail-btn" data-id="${row.asset_type}/${row.id}" data-bs-toggle="tooltip" title="Detail">
|
|
<i class="bi bi-info-circle"></i>
|
|
</button>`;
|
|
|
|
if (row.lon) {
|
|
resp = resp +
|
|
`<button class="btn btn-sm btn-light zoom-btn" data-lon="${row.lon}" data-lat="${row.lat}" data-bs-toggle="tooltip" title="Zoom">
|
|
<i class="bi bi-geo-alt"></i>
|
|
</button>`;
|
|
}
|
|
|
|
if (intervention_id) {
|
|
resp = resp +
|
|
`<button class="btn btn-sm btn-light intervention-btn" data-id="${row.id}" data-asset_type="${row.asset_type}" data-bs-toggle="tooltip" title="Ajouter à l'intervention">
|
|
<i class="bi bi-check-square"></i>
|
|
</button>`;
|
|
}
|
|
|
|
return resp;
|
|
}
|
|
|
|
|
|
|
|
// Loads features into the intersections table
|
|
function loadDataIntoIntersectionsTable(features) {
|
|
const tableData = features.map((feature) => {
|
|
return {
|
|
actions: '', // Column for the icons, manipulated by the formatter
|
|
id: feature.id,
|
|
code: feature.properties.code,
|
|
name: feature.properties.name,
|
|
status: '<i class="bi bi-circle-fill status_'+feature.properties.status+'"></i>',
|
|
lon: feature.geometry && feature.geometry.coordinates ? feature.geometry.coordinates[0] : null, // Longitude
|
|
lat: feature.geometry && feature.geometry.coordinates ? feature.geometry.coordinates[1] : null // Latitude
|
|
};
|
|
});
|
|
|
|
$('#intersections-spinner').hide();
|
|
$('#intersections-table-container').show();
|
|
$('#intersections-table').bootstrapTable('load', tableData);
|
|
}
|
|
|
|
// Loads features into the assets table
|
|
function loadDataIntoAssetsTable(features) {
|
|
const tableData = features.map((feature) => {
|
|
return {
|
|
actions: '', // Colonne pour l'icône, manipulée par le formatter
|
|
id: feature.id,
|
|
asset_type: feature.properties.asset_type,
|
|
code: feature.properties.code,
|
|
name: feature.properties.name,
|
|
model: feature.properties.model || '',
|
|
status: '<i class="bi bi-circle-fill status_'+feature.properties.status+'"></i>',
|
|
lon: feature.geometry && feature.geometry.coordinates ? feature.geometry.coordinates[0] : null, // Longitude
|
|
lat: feature.geometry && feature.geometry.coordinates ? feature.geometry.coordinates[1] : null // Latitude
|
|
};
|
|
});
|
|
$('#assets-spinner').hide();
|
|
$('#assets-table-container').show();
|
|
$('#assets-table').bootstrapTable('load', tableData);
|
|
}
|
|
|
|
|
|
|
|
function redirectToThematic() {
|
|
const select = document.getElementById('theme-select');
|
|
const selectedValue = select.value;
|
|
|
|
if (selectedValue) {
|
|
// Rediriger vers l'URL sélectionnée
|
|
window.location.href = selectedValue;
|
|
}
|
|
}
|
|
|
|
|
|
$( document ).ready(function() {
|
|
|
|
function calculateTableHeight() {
|
|
const windowHeight = $(window).height(); // Total window height
|
|
const offsetTop = 285; // Y position of the table
|
|
const footerHeight = $('.footer').outerHeight() || 0;
|
|
return windowHeight - offsetTop - footerHeight - 20;
|
|
}
|
|
|
|
$('#intersections-table').bootstrapTable({
|
|
columns: [
|
|
{ field: 'actions', title: '', formatter:'actionsFormatter', width:'130' },
|
|
{ field: 'code', title: 'Code' },
|
|
{ field: 'name', title: 'Nom' },
|
|
{ field: 'status', title: 'Statut', align: 'center' }
|
|
],
|
|
height: calculateTableHeight(), // Apply computed height
|
|
onClickRow: function (row, $element) {
|
|
// Remove highlight from all previously highlighted cells
|
|
$('#intersections-table').find('tbody td').removeClass('rowhighlight');
|
|
// Apply the highlight class to all `<td>` cells in the row
|
|
$element.find('td').addClass('rowhighlight');
|
|
|
|
// Update feature highlight on the map
|
|
highlightMapFeature(map, 'traffic-lights', row.id, intersectionshighlightState);
|
|
|
|
// Load assets GeoJSON for the selected intersection
|
|
const intersectionId = row.id;
|
|
const intersectionAssetsGeojsonUrl = `${assetsgeojsonUrl}?intersection=${intersectionId}`;
|
|
assetsgeojsonloader.loadGeojson(intersectionAssetsGeojsonUrl);
|
|
}
|
|
});
|
|
|
|
$('#assets-table').bootstrapTable({
|
|
columns: [
|
|
{ field: 'actions', title: '', formatter:'actionsFormatterAssets', width:'120' },
|
|
{ field: 'code', title: 'Code' },
|
|
{ field: 'name', title: 'Nom' },
|
|
{ field: 'model', title: 'Modèle' },
|
|
{ field: 'status', title: 'Statut', align: 'center' }
|
|
],
|
|
height: calculateTableHeight(), // Apply computed height
|
|
onClickRow: function (row, $element) {
|
|
// Remove highlight from all previously highlighted cells
|
|
$('#assets-table').find('tbody td').removeClass('rowhighlight');
|
|
// Apply the highlight class to all `<td>` cells in the row
|
|
$element.find('td').addClass('rowhighlight');
|
|
|
|
// Update feature highlight on the map
|
|
highlightMapFeature(map, 'traffic-lights-assets', row.id, assetshighlightState);
|
|
}
|
|
});
|
|
|
|
// Apply the correct width to the dropdown-menu
|
|
const parent_filter_dropdown = $('#filter-dropdown').parent().parent()[0];
|
|
const parentWidth = parent_filter_dropdown.offsetWidth - 20;
|
|
$('#filter-dropdown').width(`${parentWidth}px`);
|
|
|
|
|
|
$('#theme-select').on('change', function () {
|
|
redirectToThematic();
|
|
});
|
|
|
|
// reset view when tab is clicked (in case of window resize)
|
|
$('#locations-table-tab').on('click', function () {
|
|
$('#locations -table').bootstrapTable('resetView');
|
|
});
|
|
$('#assets-table-tab').on('click', function () {
|
|
$('#assets-table').bootstrapTable('resetView');
|
|
});
|
|
|
|
|
|
|
|
// Apply filters
|
|
document.getElementById('apply-filters').addEventListener('click', () => {
|
|
|
|
const form = document.getElementById('filter-form');
|
|
const formData = new FormData(form);
|
|
const params = new URLSearchParams();
|
|
for (const [key, value] of formData.entries()) {
|
|
if (value.trim() !== '') { // Vérifie que le champ n'est pas vide
|
|
params.append(key, value);
|
|
}
|
|
}
|
|
|
|
// Update URL
|
|
const newUrl = `${window.location.pathname}?${params.toString()}`;
|
|
window.history.pushState({}, '', newUrl);
|
|
|
|
// Load filtered data
|
|
handleGeojsonMapLoading(init=false, intersectionsgeojsonloader, 'traffic-lights', intersections_layers);
|
|
intersectionsgeojsonloader.loadGeojson(intersectionsgeojsonUrl+`?${params.toString()}`);
|
|
});
|
|
|
|
// Reset filters
|
|
document.getElementById('reset-filters').addEventListener('click', () => {
|
|
const form = document.getElementById('filter-form');
|
|
form.reset(); // Reset form fields
|
|
|
|
// Explicitly clear date fields
|
|
document.getElementById('begin_date').value = '';
|
|
|
|
// Remove URL parameters
|
|
window.history.pushState({}, '', window.location.pathname);
|
|
|
|
// Reload all data without filters
|
|
handleGeojsonMapLoading(init=false, intersectionsgeojsonloader, 'traffic-lights', intersections_layers);
|
|
intersectionsgeojsonloader.loadGeojson(intersectionsgeojsonUrl);
|
|
});
|
|
|
|
// Filter tables by map bounds
|
|
$("#filterzone").on( "click", function(e) {
|
|
e.preventDefault();
|
|
filterTableByMapBounds(map, intersections_geojson, loadDataIntoIntersectionsTable);
|
|
filterTableByMapBounds(map, assets_geojson, loadDataIntoAssetsTable);
|
|
});
|
|
|
|
|
|
// Register detail action to the tables
|
|
registerDetailAction('#intersections-table', '.detail-btn', trafficlightsintersectionsurl);
|
|
registerDetailAction('#assets-table', '.detail-btn', trafficlightsassetsurl);
|
|
|
|
// Register zoom action to the tables
|
|
registerZoomAction('#intersections-table', '.zoom-btn', map, 17);
|
|
registerZoomAction('#assets-table', '.zoom-btn', map, 18);
|
|
|
|
// Register intervention action to table assets
|
|
registerInterventionAction('#assets-table', '.intervention-btn', intervention_id);
|
|
|
|
// Register intersection selection action to table intersections
|
|
registerSelectIntersectionAction('#intersections-table', '.intersection-btn-toggle');
|
|
});
|
|
|
|
function registerInterventionAction(tableId, buttonClass, intervention_id) {
|
|
$(tableId).on('click', buttonClass, function () {
|
|
const $button = $(this);
|
|
const assetId = $(this).data('id'); // Retrieve the ID from the button's data attribute
|
|
const assetType = $(this).data('asset_type'); // Retrieve the type from the button's data attribute
|
|
|
|
if (assetId) {
|
|
linkAssetToIntervention(intervention_id, assetId, assetType, $button);
|
|
}
|
|
});
|
|
}
|
|
|
|
function linkAssetToIntervention(interventionId, assetId, assetType, $button) {
|
|
$.ajax({
|
|
url: `/interventions/${interventionId}/link-asset/`,
|
|
method: 'POST',
|
|
headers: {'X-CSRFToken': getCookie('csrftoken')},
|
|
data: {
|
|
intervention_id: interventionId,
|
|
asset_id: assetId,
|
|
model: assetType
|
|
},
|
|
success: function(response) {
|
|
// Mettre le bouton en vert et désactiver
|
|
$button
|
|
.removeClass('btn-light')
|
|
.addClass('btn-success')
|
|
.prop('disabled', true);
|
|
},
|
|
error: function(error) {
|
|
alert('Erreur lors de la liaison');
|
|
}
|
|
});
|
|
}
|
|
|
|
|
|
function registerSelectIntersectionAction(tableId, buttonClass) {
|
|
$(tableId).on('click', buttonClass, function () {
|
|
const $button = $(this);
|
|
const intersectionId = $(this).data('id'); // Retrieve the ID from the button's data attribute
|
|
|
|
if (intersectionId) {
|
|
toggleSelectedIntersection(intersectionId, $button);
|
|
}
|
|
});
|
|
}
|
|
|
|
function toggleSelectedIntersection(intersectionId, $button) {
|
|
if (selected_intersections_set.has(intersectionId)) {
|
|
selected_intersections_set.delete(intersectionId);
|
|
$button
|
|
.find('i').removeClass('bi-check-square-fill').addClass('bi-square');
|
|
} else {
|
|
selected_intersections_set.add(intersectionId);
|
|
$button
|
|
.find('i').removeClass('bi-square').addClass('bi-check-square-fill');
|
|
}
|
|
updateInputAndStatus();
|
|
}
|
|
|
|
function updateInputAndStatus() {
|
|
const inputField = document.getElementById("selected-intersections-ids");
|
|
const statusBar = document.getElementById("selection-status");
|
|
const ids = Array.from(selected_intersections_set);
|
|
inputField.value = ids.join(",");
|
|
statusBar.innerText = `${ids.length} intersection${ids.length !== 1 ? 's' : ''} sélectionnée${ids.length !== 1 ? 's' : ''}`;
|
|
}
|
|
|
|
// Selection of intersections for preventive draft
|
|
if (preventive_draft_id && preventive_draft_id !== "None") {
|
|
document.addEventListener("DOMContentLoaded", function () {
|
|
|
|
document.getElementById("select-all").addEventListener("click", () => {
|
|
const allRows = $('#intersections-table').bootstrapTable('getData');
|
|
allRows.forEach(row => {
|
|
selected_intersections_set.add(parseInt(row.id));
|
|
const btn = document.querySelector(`.intersection-btn-toggle[data-id="${row.id}"]`);
|
|
if (btn) {
|
|
$(btn).find('i').removeClass('bi-square').addClass('bi-check-square-fill');
|
|
}
|
|
});
|
|
updateInputAndStatus();
|
|
});
|
|
|
|
document.getElementById("deselect-all").addEventListener("click", () => {
|
|
selected_intersections_set.clear();
|
|
const allRows = $('#intersections-table').bootstrapTable('getData');
|
|
allRows.forEach(row => {
|
|
const btn = document.querySelector(`.intersection-btn-toggle[data-id="${row.id}"]`);
|
|
if (btn) {
|
|
$(btn).find('i').removeClass('bi-check-square-fill').addClass('bi-square');
|
|
}
|
|
});
|
|
updateInputAndStatus();
|
|
});
|
|
|
|
// Initial state
|
|
updateInputAndStatus();
|
|
});
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
function getCookie(name) {
|
|
let cookieValue = null;
|
|
if (document.cookie && document.cookie !== '') {
|
|
const cookies = document.cookie.split(';');
|
|
for (let i = 0; i < cookies.length; i++) {
|
|
const cookie = cookies[i].trim();
|
|
// Does this cookie string begin with the name we want?
|
|
if (cookie.substring(0, name.length + 1) === (name + '=')) {
|
|
cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
return cookieValue;
|
|
}
|
|
const csrftoken = getCookie('csrftoken'); |