main.html 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308
  1. {% extends "panorama/base.html" %}
  2. {% load panorama_url %}
  3. {% load static %}
  4. {% load distance_filter %}
  5. {% load i18n %}
  6. {% load l10n %}
  7. {% load utils %}
  8. {% block title %}{% trans "Celutz, a panorama viewer"%}{% endblock title %}
  9. {% block top-menu-title %}
  10. <a class="navbar-brand" href="{% url 'panorama:main' %}">Celutz</a>
  11. {% endblock %}
  12. {% block top-menu-items %}
  13. <li class="dropdown">
  14. <a href="#" id="search-menu" class="dropdown-toggle" data-toggle="dropdown"><i class="fa fa-search"></i>  {% trans "Search" %}<b class="caret"></b></a>
  15. <ul class="dropdown-menu">
  16. <li>
  17. <div style="display:table;" class="input-group">
  18. <input type="text" name="search" id="search" placeholder="{% trans "Enter an address" %}" class="form-control" />
  19. <span class="input-group-btn">
  20. <span type="button" id="search-btn" class="btn btn-primary search-btn" data-loading-text="..."><i class="fa fa-search"></i></span>
  21. </span>
  22. </div>
  23. </li>
  24. </ul>
  25. </li>
  26. {% endblock %}
  27. {% block sidebar %}
  28. <div class="collapse navbar-collapse navbar-ex1-collapse">
  29. <ul class="nav navbar-nav side-nav">
  30. {% include "panorama/sidebar-all.html" %}
  31. </ul>
  32. </div>
  33. {% endblock %}
  34. {% block wrapper-style %}
  35. {% endblock %}
  36. {% block page-wrapper-style %}
  37. style="padding:0px;height:calc(100vh - 50px)"
  38. {% endblock %}
  39. {% block content %}
  40. <div id="map"></div>
  41. <div id="modal" class="modal fade" tabindex="-1" role="dialog" aria-labelledby="Resultats" aria-hidden="true">
  42. <div class="modal-dialog modal-lg">
  43. <div class="modal-content">
  44. <div class="modal-header">
  45. <button type="button" class="close" data-dismiss="modal"><span aria-hidden="true">&times;</span><span class="sr-only">Fermer</span></button>
  46. <h4 class="modal-title" id="myModalLabel">Résultats</h4>
  47. </div>
  48. <div class="modal-body">
  49. </div>
  50. </div>
  51. </div>
  52. </div>
  53. {% endblock content %}
  54. {% block css %}
  55. <link rel="stylesheet" type="text/css" href="{% static "panorama/leaflet/v0.7.7/leaflet.css" %}">
  56. <link rel="stylesheet" type="text/css" href="{% static "panorama/css/leaflet.markercluster/0.4.0/MarkerCluster.css" %}">
  57. <link rel="stylesheet" type="text/css" href="{% static "panorama/css/leaflet.markercluster/0.4.0/MarkerCluster.Default.css" %}">
  58. <link rel="stylesheet" type="text/css" href="{% static "panorama/css/markercluster.override.css" %}" />
  59. {% endblock css %}
  60. {% block js %}
  61. {% localize off %}
  62. <script type='text/javascript' src="{% static "panorama/leaflet/v0.7.7/leaflet.js" %}"></script>
  63. <script type='text/javascript' src="{% static "panorama/js/jquery-3.0.0.min.js" %}"></script>
  64. <script type='text/javascript' src="{% static "panorama/js/leaflet.markercluster/0.4.0/leaflet.markercluster.js" %}"></script>
  65. <script>
  66. var map;
  67. var ajaxRequest;
  68. var plotlist;
  69. var plotlayers=[];
  70. var allMarkers = []
  71. var markerClusters = L.markerClusterGroup({
  72. spiderfyOnMaxZoom: false,
  73. showCoverageOnHover: false,
  74. maxClusterRadius: 20,
  75. disableClusteringAtZoom: 19
  76. });
  77. var crosshairIcon = L.icon({
  78. iconUrl: '{% static "panorama/img/marker-blue.png" %}',
  79. iconSize: [22, 35],
  80. iconAnchor: [11, 35]
  81. });
  82. var panoIcon = L.icon({
  83. iconUrl: '{% static "panorama/img/marker-red.png" %}',
  84. iconSize: [22, 35],
  85. iconAnchor: [11, 35],
  86. popupAnchor: [0,-50]
  87. });
  88. var poiIcons = {
  89. subscriber: L.icon({
  90. iconUrl: '{% static "panorama/img/marker-circle-green.png" %}',
  91. iconSize: [20, 20],
  92. iconAnchor: [10, 10],
  93. popupAnchor: [0,-20]
  94. }),
  95. waiting: L.icon({
  96. iconUrl: '{% static "panorama/img/marker-circle-orange.png" %}',
  97. iconSize: [20, 20],
  98. iconAnchor: [10, 10],
  99. popupAnchor: [0,-20]
  100. }),
  101. other: L.icon({
  102. iconUrl: '{% static "panorama/img/marker-circle-purple.png" %}',
  103. iconSize: [20, 20],
  104. iconAnchor: [10, 10],
  105. popupAnchor: [0,-20]
  106. }),
  107. };
  108. var legend = L.control({position: 'bottomright'});
  109. function accordionMenus() {
  110. $("ul.side-nav").children().click(function(e) {
  111. var menu = $(e.target);
  112. var content = menu.next();
  113. var contentid = content.attr("id");
  114. if (content.is("ul") && content.hasClass("collapse") && !content.hasClass('in')) {
  115. $(".collapse.in").each(function(){
  116. $(".collapse.in").animate({height: '1px'}, 500, function(){
  117. $(".collapse.in").not(document.getElementById(contentid)).removeClass("in");
  118. });
  119. });
  120. };
  121. });
  122. }
  123. function fillCoord() {
  124. //var lat = map.getCenter().lat.toFixed(5);
  125. //var lng = map.getCenter().lng.toFixed(5);
  126. var lat = crosshair.getLatLng().lat.toFixed(5);
  127. var lng = crosshair.getLatLng().lng.toFixed(5);
  128. $('#id_custompoint-latitude').val(lat);
  129. $('#id_newpano-latitude').val(lat);
  130. $('#id_newrefpoint-latitude').val(lat);
  131. $('#id_custompoint-longitude').val(lng);
  132. $('#id_newpano-longitude').val(lng);
  133. $('#id_newrefpoint-longitude').val(lng);
  134. $.get("/altitude/" + lat + "/" + lng + "/").done(
  135. function(data) {
  136. $('#id_custompoint-ground_altitude').val(parseInt(data));
  137. $('#id_newpano-ground_altitude').val(parseInt(data));
  138. $('#id_newrefpoint-ground_altitude').val(parseInt(data));
  139. });
  140. }
  141. function SearchPlace() {
  142. $('#search-btn').click(function(e){
  143. e.preventDefault();
  144. var btn = $(this).button('loading');
  145. // Geocoding
  146. var searchString = $('#search').val();
  147. $.getJSON('https://nominatim.openstreetmap.org/search?limit=5&format=json&q='+searchString, function(data){
  148. var items = [];
  149. $.each(data, function(key, val) {
  150. items.push(
  151. "<li class='list-group-item'><a href='#' data-lat='"+val.lat+"' data-lng='"+val.lon+"'>" + val.display_name + '</a></li>'
  152. );
  153. });
  154. $('#modal .modal-body').empty();
  155. if (items.length != 0) {
  156. $('<ul/>').addClass("list-group").html(items.join('')).appendTo('#modal .modal-body');
  157. } else {
  158. $('<p/>', { html: "Aucun résultat" }).appendTo('#modal .modal-body');
  159. }
  160. $('#modal').modal('show');
  161. // Bind click on results and update coordinates
  162. $('#modal .modal-body a').on('click', function(e){
  163. $('#modal').modal('hide');
  164. e.preventDefault();
  165. crosshair.setLatLng({lat:$(this).data('lat'), lng:$(this).data('lng')}).update();
  166. map.panTo({lat:$(this).data('lat'), lng:$(this).data('lng')});
  167. map.setZoom(19);
  168. mapUpdateCoords();
  169. });
  170. btn.button('reset');
  171. });
  172. });
  173. }
  174. function isInMapBounds(item, index, array) {
  175. {% get_setting 'MAP_BOUNDS' as bounds %}
  176. {% if bounds %}
  177. return (item[0] > {{ bounds.min_lat }})
  178. && (item[0] < {{ bounds.max_lat }})
  179. && (item[1] > {{ bounds.min_lon }})
  180. && (item[1] < {{ bounds.max_lon }});
  181. {% else %}
  182. return true;
  183. {% endif %}
  184. }
  185. function initmap() {
  186. // set up the map
  187. map = new L.Map('map');
  188. // create the tile layer with correct attribution
  189. var osmUrl = 'https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png';
  190. var osmAttrib = 'Map data © <a href="https://openstreetmap.org">OpenStreetMap</a> contributors';
  191. var osm = new L.TileLayer(osmUrl, {attribution: osmAttrib, maxZoom: 19});
  192. // start the map in Grenoble
  193. map.setView(new L.LatLng(45.1842, 5.7218),13);
  194. map.addLayer(osm);
  195. // Add in a crosshair for the map
  196. crosshair = new L.marker(map.getCenter(),{icon:crosshairIcon,draggable:true});
  197. crosshair.addTo(map);
  198. // Change crosshair lat/lon when click on the map
  199. map.on('click', function(e) {
  200. crosshair.setLatLng(e.latlng)
  201. if ($("#locate-gps,#new-pano,#new-refpoint").hasClass("collapse in")){
  202. fillCoord();
  203. }
  204. });
  205. // Move the crosshair to the center of the map when the user pans
  206. /*map.on('move', function(e) {
  207. crosshair.setLatLng(map.getCenter());
  208. });
  209. // Autofill forms while moving crosshair and expanding menus
  210. map.on('moveend', function(e) {
  211. if ($("#locate-gps,#new-pano,#new-refpoint").hasClass("collapse in")){
  212. fillCoord();
  213. }
  214. });
  215. */
  216. // Autofill forms while moving crosshair and expanding menus
  217. crosshair.on('moveend', function(e) {
  218. if ($("#locate-gps,#new-pano,#new-refpoint").hasClass("collapse in")){
  219. fillCoord();
  220. }
  221. });
  222. $('#locate-gps-btn, #new-pano-btn, #new-refpoint-btn').click(function(e) {
  223. fillCoord();
  224. });
  225. // Add searching form
  226. SearchPlace();
  227. // Create markers for panoramas
  228. {% for pano in panoramas %}
  229. var marker = L.marker([{{ pano.latitude }}, {{ pano.longitude }}], {icon: panoIcon, riseOnHover: true});
  230. marker.on("click",function(){document.location.href="{% url 'panorama:view_pano' pano.id %}"});
  231. var popup = marker.bindPopup('{{ pano.name }}',{className : 'markerpopup', closeButton: false,});
  232. popup.on('mouseover', marker.openPopup);
  233. popup.on('mouseout', marker.closePopup);
  234. markerClusters.addLayer( marker );
  235. allMarkers.push([{{ pano.latitude }}, {{ pano.longitude }}]);
  236. {% endfor %}
  237. // Filter to only take points inside the bounds (for fitting the view)
  238. fittingMarkers = allMarkers.filter(isInMapBounds);
  239. map.addLayer( markerClusters );
  240. // Add POI
  241. var pointsOfInterest = L.layerGroup();
  242. {% for poi in poi_list %}
  243. var poiMarker = L.marker([{{ poi.latitude }}, {{ poi.longitude }}], {icon: poiIcons['{{ poi.kind }}'], riseOnHover: true});
  244. var poiPopup = poiMarker.bindPopup('{{ poi.name }}', {className : 'markerpopup', closeButton: false});
  245. poiPopup.on('mouseover', poiMarker.openPopup);
  246. poiPopup.on('mouseout', poiMarker.closePopup);
  247. pointsOfInterest.addLayer(poiMarker);
  248. {% endfor %}
  249. // Add a legend to the map
  250. legend.onAdd = function (map) {
  251. var div = L.DomUtil.create('div', 'legend');
  252. div.innerHTML += '<div class="legendtitle"><p><i class="fa fa-fw fa-caret-down"></i>{% trans "Legend" %}</p></div>';
  253. div.innerHTML += '<img src={% static "panorama/img/marker-red.png" %} ><p>{% trans "Panorama" %}</p></br>';
  254. div.innerHTML += '<img src={% static "panorama/img/marker-blue.png" %} ><p>{% trans "Control" %}</p></br>';
  255. div.innerHTML += '<img src={% static "panorama/img/marker-circle-green.png" %} ><p>{% trans "Point of interest (subscriber)" %}</p></br>';
  256. div.innerHTML += '<img src={% static "panorama/img/marker-circle-orange.png" %} ><p>{% trans "Point of interest (waiting)" %}</p></br>';
  257. div.innerHTML += '<img src={% static "panorama/img/marker-circle-purple.png" %} ><p>{% trans "Point of interest (other)" %}</p></br>';
  258. return div;
  259. };
  260. map.addLayer(pointsOfInterest);
  261. map.fitBounds(fittingMarkers,{padding: [30, 30]});
  262. legend.addTo(map);
  263. }
  264. // Submit on enter keypress for the search module
  265. $('#search').keypress(function(e){
  266. if(e.which == 13) {
  267. document.getElementById("search-btn").click();
  268. }
  269. });
  270. // Put cursor on the search field for dropdown search module
  271. $('#search-menu').click(function () {
  272. setTimeout(function(){$('#search').focus();},0);
  273. });
  274. initmap();
  275. accordionMenus();
  276. </script>
  277. {% endlocalize %}
  278. {% endblock js %}