190 lines
5.7 KiB
HTML
190 lines
5.7 KiB
HTML
{% extends "mainapp/base.html" %}
|
||
{% load static %}
|
||
{% block title %}Карта объектов{% 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;
|
||
}
|
||
</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], 10);
|
||
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 markerColors = {
|
||
'blue': 'blue',
|
||
'orange': 'orange',
|
||
'green': 'green',
|
||
'violet': 'violet'
|
||
};
|
||
|
||
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 overlays = [];
|
||
|
||
// Создаём слои для каждого типа координат
|
||
{% for group in groups %}
|
||
var groupName = '{{ group.name|escapejs }}';
|
||
var colorName = '{{ group.color }}';
|
||
var groupIcon = getColorIcon(colorName);
|
||
var groupLayer = L.layerGroup();
|
||
|
||
var subgroup = [];
|
||
{% for point_data in group.points %}
|
||
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);
|
||
|
||
subgroup.push({
|
||
label: "{{ forloop.counter }} - {{ point_data.source_id|escapejs }}",
|
||
layer: marker
|
||
});
|
||
{% endfor %}
|
||
|
||
overlays.push({
|
||
label: groupName,
|
||
selectAllCheckbox: true,
|
||
children: subgroup,
|
||
layer: groupLayer
|
||
});
|
||
{% endfor %}
|
||
|
||
// Корневая группа
|
||
const rootGroup = {
|
||
label: "Все точки",
|
||
selectAllCheckbox: true,
|
||
children: overlays,
|
||
layer: L.layerGroup()
|
||
};
|
||
|
||
// Создаём tree control
|
||
const layerControl = L.control.layers.tree(baseLayers, [rootGroup], {
|
||
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>';
|
||
|
||
{% for group in groups %}
|
||
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>
|
||
`;
|
||
{% endfor %}
|
||
|
||
return div;
|
||
};
|
||
legend.addTo(map);
|
||
</script>
|
||
{% endblock extra_js %}
|