245 lines
8.4 KiB
HTML
245 lines
8.4 KiB
HTML
{% extends "mainapp/base.html" %}
|
||
{% load static %}
|
||
{% block title %}Карта объекта #{{ source_id }} с точками{% endblock title %}
|
||
|
||
{% block extra_css %}
|
||
<!-- Leaflet CSS -->
|
||
<link href="{% static 'leaflet/leaflet.css' %}" rel="stylesheet">
|
||
<link href="{% static 'leaflet-measure/leaflet-measure.css' %}" rel="stylesheet">
|
||
<link href="{% static 'leaflet-tree/L.Control.Layers.Tree.css' %}" rel="stylesheet">
|
||
<style>
|
||
body {
|
||
overflow: hidden;
|
||
}
|
||
#map {
|
||
position: fixed;
|
||
top: 56px; /* Высота navbar */
|
||
bottom: 0;
|
||
left: 0;
|
||
right: 0;
|
||
z-index: 1;
|
||
}
|
||
.legend {
|
||
background: white;
|
||
padding: 8px;
|
||
border-radius: 4px;
|
||
box-shadow: 0 0 10px rgba(0,0,0,0.2);
|
||
font-size: 11px;
|
||
}
|
||
.legend h6 {
|
||
font-size: 12px;
|
||
margin: 0 0 6px 0;
|
||
}
|
||
.legend-item {
|
||
margin: 3px 0;
|
||
display: flex;
|
||
align-items: center;
|
||
}
|
||
.legend-marker {
|
||
width: 18px;
|
||
height: 30px;
|
||
margin-right: 6px;
|
||
background-size: contain;
|
||
background-repeat: no-repeat;
|
||
}
|
||
.legend-section {
|
||
margin-top: 8px;
|
||
padding-top: 8px;
|
||
border-top: 1px solid #ddd;
|
||
}
|
||
.legend-section:first-child {
|
||
margin-top: 0;
|
||
padding-top: 0;
|
||
border-top: none;
|
||
}
|
||
.legend-section-title {
|
||
font-weight: bold;
|
||
font-size: 11px;
|
||
margin-bottom: 4px;
|
||
}
|
||
</style>
|
||
{% endblock %}
|
||
|
||
{% block content %}
|
||
<div id="map"></div>
|
||
{% endblock content %}
|
||
|
||
{% block extra_js %}
|
||
<!-- Leaflet JavaScript -->
|
||
<script src="{% static 'leaflet/leaflet.js' %}"></script>
|
||
<script src="{% static 'leaflet-measure/leaflet-measure.ru.js' %}"></script>
|
||
<script src="{% static 'leaflet-tree/L.Control.Layers.Tree.js' %}"></script>
|
||
|
||
<script>
|
||
// Инициализация карты
|
||
let map = L.map('map').setView([55.75, 37.62], 5);
|
||
L.control.scale({
|
||
imperial: false,
|
||
metric: true
|
||
}).addTo(map);
|
||
map.attributionControl.setPrefix(false);
|
||
|
||
const street = L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
|
||
maxZoom: 19,
|
||
attribution: '© <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors'
|
||
});
|
||
street.addTo(map);
|
||
|
||
const satellite = L.tileLayer('https://server.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer/tile/{z}/{y}/{x}', {
|
||
attribution: 'Tiles © Esri'
|
||
});
|
||
|
||
const street_local = L.tileLayer('http://127.0.0.1:8080/styles/basic-preview/{z}/{x}/{y}.png', {
|
||
maxZoom: 19,
|
||
attribution: 'Local Tiles'
|
||
});
|
||
|
||
const baseLayers = {
|
||
"Улицы": street,
|
||
"Спутник": satellite,
|
||
"Локально": street_local
|
||
};
|
||
|
||
L.control.layers(baseLayers).addTo(map);
|
||
map.setMaxZoom(18);
|
||
map.setMinZoom(0);
|
||
L.control.measure({ primaryLengthUnit: 'kilometers' }).addTo(map);
|
||
|
||
// Функция для создания иконки
|
||
var getColorIcon = function(color) {
|
||
return L.icon({
|
||
iconUrl: '{% static "leaflet-markers/img/marker-icon-" %}' + color + '.png',
|
||
shadowUrl: '{% static "leaflet-markers/img/marker-shadow.png" %}',
|
||
iconSize: [25, 41],
|
||
iconAnchor: [12, 41],
|
||
popupAnchor: [1, -34],
|
||
shadowSize: [41, 41]
|
||
});
|
||
};
|
||
|
||
var sourceOverlays = [];
|
||
var glPointLayers = [];
|
||
|
||
// Создаём слои для координат объекта и точек ГЛ
|
||
{% for group in groups %}
|
||
var groupName = '{{ group.name|escapejs }}';
|
||
var colorName = '{{ group.color }}';
|
||
var groupIcon = getColorIcon(colorName);
|
||
var groupLayer = L.layerGroup();
|
||
|
||
{% for point_data in group.points %}
|
||
{% if point_data.source_id %}
|
||
// Это координата объекта
|
||
var pointName = "{{ point_data.source_id|escapejs }}";
|
||
var marker = L.marker([{{ point_data.point.1|safe }}, {{ point_data.point.0|safe }}], {
|
||
icon: groupIcon
|
||
}).bindPopup(pointName);
|
||
groupLayer.addLayer(marker);
|
||
{% else %}
|
||
// Это точка ГЛ
|
||
var pointName = "{{ point_data.name|escapejs }}";
|
||
var marker = L.marker([{{ point_data.point.1|safe }}, {{ point_data.point.0|safe }}], {
|
||
icon: groupIcon
|
||
}).bindPopup(pointName + '<br>' + "{{ point_data.frequency|escapejs }}");
|
||
groupLayer.addLayer(marker);
|
||
|
||
// Добавляем каждую точку ГЛ отдельно в список
|
||
glPointLayers.push({
|
||
label: "{{ forloop.counter }} - {{ point_data.name|escapejs }} ({{ point_data.frequency|escapejs }})",
|
||
layer: marker
|
||
});
|
||
{% endif %}
|
||
{% endfor %}
|
||
|
||
// Для координат объекта добавляем как отдельный слой без вложенности
|
||
{% if group.color in 'blue,orange,green,violet' %}
|
||
sourceOverlays.push({
|
||
label: groupName,
|
||
layer: groupLayer
|
||
});
|
||
{% endif %}
|
||
{% endfor %}
|
||
|
||
// Создаём иерархию
|
||
var treeOverlays = [];
|
||
|
||
if (sourceOverlays.length > 0) {
|
||
treeOverlays.push({
|
||
label: "Координаты объекта #{{ source_id }}",
|
||
selectAllCheckbox: true,
|
||
children: sourceOverlays,
|
||
layer: L.layerGroup()
|
||
});
|
||
}
|
||
|
||
if (glPointLayers.length > 0) {
|
||
treeOverlays.push({
|
||
label: "Точки ГЛ",
|
||
selectAllCheckbox: true,
|
||
children: glPointLayers,
|
||
layer: L.layerGroup()
|
||
});
|
||
}
|
||
|
||
// Создаём tree control
|
||
const layerControl = L.control.layers.tree(baseLayers, treeOverlays, {
|
||
collapsed: false,
|
||
autoZIndex: true
|
||
});
|
||
layerControl.addTo(map);
|
||
|
||
// Подгоняем карту под все маркеры
|
||
{% if groups %}
|
||
var groupBounds = L.featureGroup([]);
|
||
{% for group in groups %}
|
||
{% for point_data in group.points %}
|
||
groupBounds.addLayer(L.marker([{{ point_data.point.1|safe }}, {{ point_data.point.0|safe }}]));
|
||
{% endfor %}
|
||
{% endfor %}
|
||
map.fitBounds(groupBounds.getBounds().pad(0.1));
|
||
{% endif %}
|
||
|
||
// Добавляем легенду в левый нижний угол
|
||
var legend = L.control({ position: 'bottomleft' });
|
||
legend.onAdd = function(map) {
|
||
var div = L.DomUtil.create('div', 'legend');
|
||
div.innerHTML = '<h6><strong>Легенда</strong></h6>';
|
||
|
||
// Координаты объекта
|
||
var hasSourceCoords = false;
|
||
{% for group in groups %}
|
||
{% if group.color in 'blue,orange,green,violet' %}
|
||
{% if not hasSourceCoords %}
|
||
if (!hasSourceCoords) {
|
||
div.innerHTML += '<div class="legend-section-title">Координаты объекта:</div>';
|
||
hasSourceCoords = true;
|
||
}
|
||
{% endif %}
|
||
div.innerHTML += `
|
||
<div class="legend-item">
|
||
<div class="legend-marker" style="background-image: url('{% static "leaflet-markers/img/marker-icon-" %}{{ group.color }}.png');"></div>
|
||
<span>{{ group.name|escapejs }}</span>
|
||
</div>
|
||
`;
|
||
{% endif %}
|
||
{% endfor %}
|
||
|
||
// Точки ГЛ (все одним цветом)
|
||
{% for group in groups %}
|
||
{% if group.color not in 'blue,orange,green,violet' %}
|
||
div.innerHTML += '<div class="legend-section"><div class="legend-section-title">Точки ГЛ:</div></div>';
|
||
div.innerHTML += `
|
||
<div class="legend-item">
|
||
<div class="legend-marker" style="background-image: url('{% static "leaflet-markers/img/marker-icon-" %}{{ group.color }}.png');"></div>
|
||
<span>{{ group.name|escapejs }}</span>
|
||
</div>
|
||
`;
|
||
{% endif %}
|
||
{% endfor %}
|
||
|
||
return div;
|
||
};
|
||
legend.addTo(map);
|
||
</script>
|
||
{% endblock extra_js %}
|