markers = []; function getMapBigIconByStatus(status_id) { if (status_id == 1) return "marker_on.svg"; if (status_id == 2) return "marker_off.svg"; if (status_id == 3) return "marker_none.svg"; if (status_id == 4) return "marker_stopped.svg"; if (status_id == -2) return "marker_unknown.svg"; return "marker_none.svg"; } function getMapSmallIconByStatus(status_id) { if (status_id == 1) return "marker_small_on.svg"; if (status_id == 2) return "marker_small_off.svg"; if (status_id == 3) return "marker_small_none.svg"; if (status_id == 4) return "marker_small_stopped.svg"; if (status_id == -2) return "marker_small_unknown.svg"; return "marker_small_none.svg"; } function getFilterByStatus(status_id) { //https://codepen.io/sosuke/pen/Pjoqqp if (status_id == 1) return "invert(46%) sepia(25%) saturate(7045%) hue-rotate(86deg) brightness(96%) contrast(106%)"; //on if (status_id == 2) return "invert(12%) sepia(81%) saturate(3912%) hue-rotate(318deg) brightness(80%) contrast(116%)"; //off if (status_id == 3) return ""; if (status_id == 4) return "invert(53%) sepia(43%) saturate(3005%) hue-rotate(35deg) brightness(121%) contrast(101%)"; //stopped if (status_id == -2) return "invert(35%) sepia(35%) saturate(2523%) hue-rotate(171deg) brightness(88%) contrast(98%)"; //unknown return ""; } function generatePopupForMarker(address, channel) { var s = "Адреса: " + address.replace("->", '') + "
"; var info = generateStringChannelState(channel, true); if (info.length > 1) s += info + "
"; s += "Канал: @" + channel.link + " ( " + channel.users + ")"; if (channel.timetable_template_name != null && channel.timetable_template_name.length > 2) { s += '
Розклад: ' + channel.timetable_template_name.replace('->', '') + ""; } if (channel.channel_id >= 0) { s += "

Редагувати канал " + channel.channel_id + ""; } return s; } /*function getDistanceBetween2Coords(lat1, lng1, lat2, lng2) { return Math.sqrt(Math.pow(lat1 - lat2, 2) + Math.pow(lng1 - lng2, 2)); } function getDistanceBetween2Markers(marker1, marker2) { return getDistanceBetween2Coords(marker1.getLatLng().lat, marker1.getLatLng().lng, marker2.getLatLng().lat, marker2.getLatLng().lng); }*/ function drawLineOnMap(lat1, lng1, lat2, lng2, color) { var pointA = new L.LatLng(lat1, lng1); var pointB = new L.LatLng(lat2, lng2); var pointList = [pointA, pointB]; var line = new L.polyline(pointList, { color: color, weight: 3, opacity: 0.5, smoothFactor: 1 }); map.addLayer(line); } function drawLineOnMapBetweenMarkers(marker1, marker2, color) { drawLineOnMap(marker1.getLatLng().lat, marker1.getLatLng().lng, marker2.getLatLng().lat, marker2.getLatLng().lng, color); } function haversineDistance(lat1, lng1, lat2, lng2) { var R = 6371e3; // radius of the earth in meters var φ1 = lat1 * (Math.PI / 180); var φ2 = lat2 * (Math.PI / 180); var Δφ = (lat2 - lat1) * (Math.PI / 180); var Δλ = (lng2 - lng1) * (Math.PI / 180); var a = Math.sin(Δφ / 2) * Math.sin(Δφ / 2) + Math.cos(φ1) * Math.cos(φ2) * Math.sin(Δλ / 2) * Math.sin(Δλ / 2); var c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a)); var d = R * c; // distance in meters return d; } function getMarkerCircleStyle(percentage1, color1, percentage2, color2, percentage3, color3, percentage4, color4) { return `background: linear-gradient(to right, ${color1} 0%, ${color1} ${percentage1}%, ${color2} ${percentage1}%, ${color2} ${percentage1 + percentage2}%, ${color3} ${percentage1 + percentage2}%, ${color3} ${percentage1 + percentage2 + percentage3}%, ${color4} ${percentage1 + percentage2 + percentage3}%, ${color4} 100%) 0 0 / 100% 100% no-repeat;`; } var markerCluster = null; function handleClusterSubElements() { var arr = markerCluster.getLayers(); arr = arr.filter(function(marker) { return marker._icon != null; }); map.eachLayer(function(layer) { if (layer instanceof L.Polyline) { map.removeLayer(layer); } }); var point_icon_width = 20; var point_icon_height = 20; var point_marker_z_index = 10; var connected_markers_array = []; for (var i in arr) { var marker = arr[i]; if (marker.channel == null) continue; //connected points var point_icon_path = "assets/media/map_img/icon_small/" + getMapSmallIconByStatus(marker.channel.status_id); var point_icon = L.icon({ iconUrl: point_icon_path, iconSize: [point_icon_width, point_icon_height], iconAnchor: [point_icon_width / 2, point_icon_height / 2] }); if (marker.channel != null && marker.channel.connected_points != null && marker.channel.connected_points.length > 0) { for (var i in marker.connected_markers) { markerCluster.removeLayer(marker.connected_markers[i]); } marker.connected_markers = []; //connect with anchor for (var i in marker.channel.connected_points) { var point = marker.channel.connected_points[i]; var point_popup = generatePopupForMarker(point.name, marker.channel); //find same marker var same_marker = null; for (var i2 in connected_markers_array) { var already_marker = connected_markers_array[i2]; if (haversineDistance(already_marker.getLatLng().lat, already_marker.getLatLng().lng, point.latitude, point.longitude) <= 1) { same_marker = already_marker; break; } }; if (same_marker != null) { same_marker.bindPopup(same_marker.getPopup().getContent() + "

" + point_popup); drawLineOnMapBetweenMarkers(marker, same_marker, getColorByStatus(marker.channel.status_id)) continue; } else { var point_marker = L.marker([point.latitude, point.longitude], { icon: point_icon }).addTo(markerCluster); point_marker.bindPopup(point_popup); point_marker.setZIndexOffset(point_marker_z_index); point_marker.channel = null; marker.connected_markers.push(point_marker); connected_markers_array.push(point_marker); drawLineOnMapBetweenMarkers(marker, point_marker, getColorByStatus(marker.channel.status_id)) } } } } } function mapFlyTo(lat, lng, zoom) { map.flyTo([lat, lng], zoom, { animate: true, duration: 1.5 }); } function plotChannelsOnMap(channels) { markers = []; var first = true; var icon_size = 30; var icon_width = icon_size; var icon_height = icon_size * 4 / 3; var marker_z_index = 20; let urlParams = new URLSearchParams(window.location.search); let zoom_to_channel_link = urlParams.get('zoom_to_channel_link'); if (zoom_to_channel_link == null) { zoom_to_channel_link = "-1"; } var is_grouping_enabled = $("#dataForm_checkBox").is(":checked"); var cluster_zoom = is_grouping_enabled ? 14 : -1; //cluster_zoom.removeFrom(map); if (markerCluster != null) { map.removeLayer(markerCluster); } markerCluster = L.markerClusterGroup({ disableClusteringAtZoom: cluster_zoom, zoomToBoundsOnClick: true, spiderfyOnMaxZoom: false, showCoverageOnHover: false, iconCreateFunction: function(cluster) { var childCount = cluster.getChildCount(); var c = ' my-marker-cluster-'; if (childCount < 10) { c += 'small'; } else if (childCount < 100) { c += 'medium'; } else { c += 'large'; } var statuses = {}; cluster.getAllChildMarkers().forEach(function(marker) { if (marker.channel != null) { var status = marker.channel.status_id; if (!statuses[status]) { statuses[status] = 1; } statuses[status]++; } }); var total_on = statuses[1]; var total_off = statuses[2]; var total_stopped = statuses[3]; var total_unknown = statuses[-2]; // added line total_on = total_on == null ? 0 : total_on; total_off = total_off == null ? 0 : total_off; total_stopped = total_stopped == null ? 0 : total_stopped; total_unknown = total_unknown == null ? 0 : total_unknown; // added line var total = total_on + total_off + total_stopped + total_unknown; // modified line var s_style = 'style="' + getMarkerCircleStyle( total_on / total * 100, "#00e300", total_off / total * 100, "#ff0000", total_stopped / total * 100, "#c5c5c4", total_unknown / total * 100, "#009ef7") + '"'; // modified line var icon = new L.DivIcon({ html: '
' + childCount + '
', className: 'marker-cluster' + c, iconSize: new L.Point(40, 40), }); return icon; } }); map.on('zoomend', function() { setTimeout(handleClusterSubElements, 400); var zoomLevel = map.getZoom(); var is_grouping_enabled = $("#dataForm_checkBox").is(":checked"); $('.custom-icon-crown').css("display", is_grouping_enabled || zoomLevel >= 12 ? "block" : "none"); }); map.on('zoomstart', function() { handleClusterSubElements(); }); channels = channels.sort(function(a, b) { return b.users - a.users; }); var total_light_on = 0; var total_light_off = 0; var total_light_stopped = 0; var total_light_unknown = 0; for (var i in channels) { var channel = channels[i]; if (channel.users <= 0 || isNaN(channel.status_id)) continue; if (channel.status_id == 1) { total_light_on++; } else if (channel.status_id == 2) { total_light_off++; } else if (channel.status_id == 3) { total_light_stopped++; }else if (channel.status_id == -2) { total_light_unknown++; } var icon_path = "assets/media/map_img/icon_big/" + getMapBigIconByStatus(channel.status_id); var icon_html_with_crown_small = '' var icon_html_with_crown_big = '' var icon = L.icon({ iconUrl: icon_path, iconSize: [icon_width, icon_height], iconAnchor: [icon_width / 2, icon_height], popupAnchor: [0, -icon_height - 5] }); var custom_html = ''; if (channel.users > 250) { custom_html += icon_html_with_crown_small; } if (channel.users > 1000) { custom_html += icon_html_with_crown_big; } //ping_type var icon_inside_style_phone = ""; var icon_inside_style_router = ""; var icon_inside_style_router_double = ""; if (!isAdminPWDused) { icon_inside_style_phone = "filter: " + getFilterByStatus(channel.status_id); icon_inside_style_router = icon_inside_style_phone; icon_inside_style_router_double = icon_inside_style_phone; } else { icon_inside_style_phone = "filter: invert(23%) sepia(62%) saturate(6028%) hue-rotate(219deg) brightness(95%) contrast(94%)"; icon_inside_style_router_double = "filter: invert(20%) sepia(100%) saturate(2603%) hue-rotate(291deg) brightness(112%) contrast(140%)" } var icon_phone = '' var icon_router = '' var icon_router_double = '' custom_html += [icon_phone, icon_router, icon_router_double][channel.ping_type]; console.log(icon_phone); if (custom_html != null) { var customIcon = L.DivIcon.extend({ options: { className: "", iconSize: [icon_width, icon_height], iconAnchor: [icon_width / 2, icon_height], popupAnchor: [0, -icon_height - 5], html: custom_html } }); icon = new customIcon(); } //check marker overlap same_marker = null; for (var i in markers) { var m = markers[i]; if (haversineDistance(m.getLatLng().lat, m.getLatLng().lng, channel.latitude, channel.longitude) <= 1) { same_marker = m; break; } }; if (same_marker != null) { same_marker.bindPopup(same_marker.getPopup().getContent() + "

" + generatePopupForMarker(channel.title, channel)); continue; } var marker = L.marker([channel.latitude, channel.longitude], { icon: icon }).addTo(markerCluster); marker.bindPopup(generatePopupForMarker(channel.title, channel)); marker.setZIndexOffset(marker_z_index); marker.channel = channel; marker.connected_markers = []; markers.push(marker); if (marker.channel.has_user_allowed_to_show == false) { marker.options.icon.options.className = 'dark-icon'; } if (zoom_to_channel_link === marker.channel.link) { mapFlyTo(channel.latitude, channel.longitude, 16); } } map.addLayer(markerCluster); $('.custom-icon-crown').css("display", is_grouping_enabled ? "block" : "none"); $("#myStats").css("display", "block"); $("#myStats_total_on").html("" + total_light_on + 'Світло є'); $("#myStats_total_off").html("" + total_light_off + 'Світла немає'); $("#myStats_total_stopped").html("" + total_light_stopped + 'Тех. перерва'); $("#myStats_total_unknown").html("" + total_light_unknown + 'Пов. тривога'); } function getChannelMapDataFromString(s) { if (s.length < 3) return null; var split = s.split(";&&&;"); if (split.length != 12) return null; var channel_id = parseInt(split[0].trim()); var status_id = parseInt(split[1].trim()); var status_changed_at = new Date(split[2].trim()); var name = split[3].trim(); var tg_link = split[4].trim(); var users_cnt = parseInt(split[5].trim()); var latitude = parseFloat(split[6].trim()); var longitude = parseFloat(split[7].trim()); ping_type = parseInt(split[8].trim()); var timetable_template_name = split[9].trim(); var has_user_allowed_to_show = parseInt(split[10].trim()) == 1; var s_connected_points = split[11].trim(); var connected_points = []; if (s_connected_points.length > 0) { var split_points = s_connected_points.split(";&&;"); for (var i = 0; i < split_points.length; i++) { var point_data = split_points[i].split(";&;"); if (point_data.length != 3) continue; var point_name = point_data[0].trim(); var point_latitude = parseFloat(point_data[1].trim()); var point_longitude = parseFloat(point_data[2].trim()); var point = { name: point_name, latitude: point_latitude, longitude: point_longitude } connected_points.push(point); } } if (isNaN(status_id)) status_id = 0; return { channel_id: channel_id, status_id: status_id, status_changed_at: status_changed_at, ping_type: ping_type, link: tg_link, title: name, users: users_cnt, latitude: latitude, longitude: longitude, timetable_template_name: timetable_template_name, has_user_allowed_to_show: has_user_allowed_to_show, connected_points: connected_points } } var isAdminPWDused = false; function loadChannelsForMap(_callback) { let urlParams = new URLSearchParams(window.location.search); let map_admin_pwd = urlParams.get('pwd'); // удачи подобрать md5 hash пароль) var url = PYTHON_API_URL + "website/getChannelsForMap"; if (map_admin_pwd != null && map_admin_pwd.length > 10) { url += "?pwd=" + map_admin_pwd; isAdminPWDused = true; } $.get(url).done(function(data) { var total_users_cnt = 0; // Set the array of parameters var channels_arr = []; var split = data.split("\n"); for (var i = 0; i < split.length; i++) { var line = split[i]; el = getChannelMapDataFromString(line); if (el == null || isNaN(el.latitude) || isNaN(el.longitude)) continue; channels_arr.push(el); } plotChannelsOnMap(channels_arr); _callback(); let autofill_suggestions = []; for (var i in channels_arr) { var channel = channels_arr[i]; if (channel == null) continue; autofill_suggestions.push(channel.title); autofill_suggestions.push(channel.link); if (channel.connected_points == null || channel.connected_points.length == 0) continue; for (var j in channel.connected_points) { var name = channel.connected_points[j].name; autofill_suggestions.push(name); } } // getting all required elements applyAutocompleteSearchBar("#search-input", autofill_suggestions); }); } function toggleStatsVisibility() { var current_state = $("#myStatsMainContainer").css("display"); if (current_state == "block") { statsHide(); } else { statsShow(); } } function statsHide() { $("#myStatsMainContainer").css("display", "none"); $("#myStats").css("width", "20px"); $("#dropdown_button").removeAttr('class'); $("#dropdown_button").attr('class', 'fa fa-arrow-down'); } function statsShow() { $("#myStatsMainContainer").css("display", "block"); $("#myStats").css("width", "170"); $("#dropdown_button").removeAttr('class'); $("#dropdown_button").attr('class', 'fa fa-arrow-up'); } function createOwnChannel() { var url = "https://svitlobot.in.ua"; window.open(url,"_blank"); } function findMarkerByTitleOrLink(query) { for (var i in markers) { var marker = markers[i]; if (marker.channel == null) continue; if (marker.channel.title === query || marker.channel.link === query) return [marker, marker.channel.latitude, marker.channel.longitude]; if (marker.channel.connected_points == null || marker.channel.connected_points.length == 0) continue; for (var j in marker.connected_markers) { var c_marker = marker.channel.connected_points[j]; if (c_marker.name == query) { return [marker, c_marker.latitude, c_marker.longitude]; } } } return null; } function onSearchBarClick(query) { var data = findMarkerByTitleOrLink(query); if (data == null) { alert('Нажаль, цей канал не знайдено на мапі ('); return; } mapFlyTo(data[1], data[2], 16); setTimeout(function(marker) { marker.openPopup(); }, 1700, data[0]); } var map; $(document).ready(function() { map = L.map('map').setView([48.3794, 31.1656], 6); var bounds = L.latLngBounds([ [30.0, 5.0], // Southernmost and westernmost points [70.0, 60.0] // Northernmost and easternmost points ]); map.setMaxBounds(bounds); L.tileLayer("https://mt1.google.com/vt/lyrs=r&x={x}&y={y}&z={z}", { minZoom: 3, maxZoom: 20, id: "google.street" }).addTo(map); $('#map').loadingOverlay(true, { backgroundColor: 'rgba(0,0,0,0.67)', }); loadChannelsForMap(() => { $('#map').loadingOverlay(false, {}); }); var localStorageProp = localStorage.getItem("isGroupingEnabled"); if (localStorageProp != null) { $("#dataForm_checkBox").prop("checked", localStorageProp == 1); } $("#dataForm_checkBox").click(function() { localStorage.setItem("isGroupingEnabled", $("#dataForm_checkBox").is(":checked") ? 1 : 0); $('#map').loadingOverlay(true, { backgroundColor: 'rgba(0,0,0,0.67)', }); loadChannelsForMap(() => { $('#map').loadingOverlay(false, {}); }); }); statsShow(); if ($(window).width() < $(window).height()) { statsHide(); } });