Files
simplemap/public/index.html
2024-01-01 21:40:47 +02:00

24 KiB

<html lang="en"> <head> <script src="https://unpkg.com/leaflet@1.9.4/dist/leaflet.js" integrity="sha256-20nQCchB9co0qIjJZRGuk2/Z9VM+kNiyxNV1lvTlZBo=" crossorigin=""></script> <script src="https://cdn.socket.io/4.5.4/socket.io.min.js"></script> <script src="https://cdn.jsdelivr.net/gh/gokertanrisever/leaflet-ruler@master/src/leaflet-ruler.js" crossorigin="anonymous"></script> <script src="https://unpkg.com/leaflet-auto-graticule@1.1.2/dist/L.AutoGraticule.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/leaflet-minimap/3.6.1/Control.MiniMap.js" integrity="sha512-ceQPs2CHke3gSINLt/JV37W1rfJOM64yuH999hnRhTP7tNtcSBp5hlTKhn8CEIhsFweSBrZMPVotAKjoyxGWNg==" crossorigin="anonymous" referrerpolicy="no-referrer"></script> <script src="https://cdn.jsdelivr.net/npm/notyf@3/notyf.min.js"></script> <style> body { margin: 0; touch-action: none; font-family: Arial, Helvetica, sans-serif; } #placeholder { position: absolute; width: 100vw; height: 100vh; background-color: #a4a4a4; color: black; font-size: 16px; font-family: monospace; z-index: 99999; display: flex; justify-content: center; align-items: center; flex-direction: column; } #map { position: absolute; top: 0px; bottom: 0px; left: 0px; right: 0px; height: 100vh; touch-action: none; width: 100vw; } #log { position: absolute; width: 870px; color: #fafafa; right: 0; font-family: monospace; background-color: rgba(0, 0, 0, 0.5); /*display: none;*/ z-index: 99999; } #users { position: absolute; width: 100vw; color: #fafafa; bottom: 0; vertical-align: middle; font-family: monospace; background-color: rgba(0, 0, 0, 0.5); /*display: none;*/ z-index: 99999; line-height: 26px; display: flex; justify-content: center; font-size: 20px; } #hint { position: absolute; width: 200px; color: #fafafa; top: 0; left: 50px; vertical-align: middle; font-family: monospace; background-color: rgba(0, 0, 0, 0.5); /*display: none;*/ z-index: 99999; display: flex; justify-content: center; font-size: 11px; } </style> </head>
loading...
* Space - toggle drawing
* 10m save for 500 last lines
<script> var notyf = new Notyf({ duration: 1000, position: { x: 'center', y: 'bottom', }, types: [ { type: 'success', background: 'green', dismissible: false, }, { type: 'error', background: 'indianred', duration: 2000, dismissible: false }, { type: 'info', icon: { className: 'notyf__icon--success', tagName: 'i', }, background: '#0096f6', duration: 2000, dismissible: false } ] }); var socket = io(); var randomColor; var myId = 0; const userDiv = document.getElementById('users'); L.Map.mergeOptions({ touchExtend: true }); L.Map.TouchExtend = L.Handler.extend({ // @method initialize(): void // Sets TouchExtend private accessor variables initialize: function (map) { this._map = map; this._container = map._container; this._pane = map._panes.overlayPane; }, // @method addHooks(): void // Adds dom listener events to the map container addHooks: function () { L.DomEvent.on(this._container, 'touchstart', this._onTouchStart, this); L.DomEvent.on(this._container, 'touchend', this._onTouchEnd, this); L.DomEvent.on(this._container, 'touchmove', this._onTouchMove, this); L.DomEvent.on(this._container, 'touchcancel', this._onTouchCancel, this); L.DomEvent.on(this._container, 'touchleave', this._onTouchLeave, this); }, // @method removeHooks(): void // Removes dom listener events from the map container removeHooks: function () { L.DomEvent.off(this._container, 'touchstart', this._onTouchStart, this); L.DomEvent.off(this._container, 'touchend', this._onTouchEnd, this); L.DomEvent.off(this._container, 'touchmove', this._onTouchMove, this); L.DomEvent.off(this._container, 'touchcancel', this._onTouchCancel, this); L.DomEvent.off(this._container, 'touchleave', this._onTouchLeave, this); }, _touchEvent: function (e, type) { // #TODO: fix the pageX error that is do a bug in Android where a single touch triggers two click events // _filterClick is what leaflet uses as a workaround. // This is a problem with more things than just android. Another problem is touchEnd has no touches in // its touch list. var touchEvent = {}; if (typeof e.touches !== 'undefined') { if (!e.touches.length) { if (type === 'touchend') { this._map.fire(type, { originalEvent: e }); return; } return; } touchEvent = e.touches[0]; } else if (e.pointerType === 'touch') { touchEvent = e; if (!this._filterClick(e)) { return; } } else { return; } var containerPoint = this._map.mouseEventToContainerPoint(touchEvent), layerPoint = this._map.mouseEventToLayerPoint(touchEvent), latlng = this._map.layerPointToLatLng(layerPoint); this._map.fire(type, { latlng: latlng, layerPoint: layerPoint, containerPoint: containerPoint, pageX: touchEvent.pageX, pageY: touchEvent.pageY, originalEvent: e }); }, /** Borrowed from Leaflet and modified for bool ops **/ _filterClick: function (e) { var timeStamp = (e.timeStamp || e.originalEvent.timeStamp), elapsed = L.DomEvent._lastClick && (timeStamp - L.DomEvent._lastClick); // are they closer together than 500ms yet more than 100ms? // Android typically triggers them ~300ms apart while multiple listeners // on the same event should be triggered far faster; // or check if click is simulated on the element, and if it is, reject any non-simulated events if ((elapsed && elapsed > 100 && elapsed < 500) || (e.target._simulatedClick && !e._simulated)) { L.DomEvent.stop(e); return false; } L.DomEvent._lastClick = timeStamp; return true; }, _onTouchStart: function (e) { if (!this._map._loaded) { return; } var type = 'touchstart'; this._touchEvent(e, type); }, _onTouchEnd: function (e) { if (!this._map._loaded) { return; } var type = 'touchend'; this._touchEvent(e, type); }, _onTouchCancel: function (e) { if (!this._map._loaded) { return; } var type = 'touchcancel'; if (this._detectIE()) { type = 'pointercancel'; } this._touchEvent(e, type); }, _onTouchLeave: function (e) { if (!this._map._loaded) { return; } var type = 'touchleave'; this._touchEvent(e, type); }, _onTouchMove: function (e) { if (!this._map._loaded) { return; } var type = 'touchmove'; this._touchEvent(e, type); }, }); L.Map.addInitHook('addHandler', 'touchExtend', L.Map.TouchExtend); var map = L.map('map', { dragging: true, doubleClickZoom: false, minZoom: 4, }).setView([48.8659904, 31.3847594], 7); L.Map.mergeOptions({ touchExtend: true }); L.control.ruler().addTo(map); new L.AutoGraticule().addTo(map); var Temp = L.tileLayer( "https://tile.openweathermap.org/map/temp_new/{z}/{x}/{y}.png?appid=d22d9a6a3ff2aa523d5917bbccc89211", { maxZoom: 18, attribution: '© VANE', id: "temp" } ), Precipitation = L.tileLayer( "https://tile.openweathermap.org/map/precipitation_new/{z}/{x}/{y}.png?appid=d22d9a6a3ff2aa523d5917bbccc89211", { maxZoom: 18, attribution: '© VANE' } ), Wind = L.tileLayer( "https://tile.openweathermap.org/map/wind_new/{z}/{x}/{y}.png?appid=d22d9a6a3ff2aa523d5917bbccc89211", { maxZoom: 18, attribution: '© VANE' } ), Pressure = L.tileLayer( "https://tile.openweathermap.org/map/pressure_new/{z}/{x}/{y}.png?appid=d22d9a6a3ff2aa523d5917bbccc89211", { maxZoom: 18, attribution: '© VANE' } ), Clouds = L.tileLayer( "https://tile.openweathermap.org/map/clouds_new/{z}/{x}/{y}.png?appid=d22d9a6a3ff2aa523d5917bbccc89211", { maxZoom: 18, attribution: '© VANE' } ); //Temp.addTo(map); const getMapLocation = function (zoom, center) { 'use strict'; zoom = (zoom || zoom === 0) ? zoom : 7; center = (center) ? center : [48.8659904, 31.3847594]; if (window.location.hash !== '') { var hash = window.location.hash.replace('#', ''); var parts = hash.split(','); if (parts.length === 3) { center = { lat: parseFloat(parts[0]), lng: parseFloat(parts[1]) }; zoom = parseInt(parts[2].slice(0, -1), 10); } } return {zoom: zoom, center: center}; } var hash = getMapLocation(); map.setView(hash.center, hash.zoom); map.on('moveend', function () { var center = map.getCenter(); var hash = '#' + Math.round(center.lat * 100000) / 100000 + ',' + Math.round(center.lng * 100000) / 100000 + ',' + map.getZoom() + 'z'; var state = { zoom: map.getZoom(), center: center }; window.history.pushState(state, 'map', hash); }); var OpenStreetMap_Mapnik = L.tileLayer('https://tile.openstreetmap.org/{z}/{x}/{y}.png', { maxZoom: 19, attribution: '© OpenStreetMap contributors' }); var OpenTopoMap = L.tileLayer('https://{s}.tile.opentopomap.org/{z}/{x}/{y}.png', { maxZoom: 17, attribution: 'Map data: © OpenStreetMap contributors, SRTM | Map style: © OpenTopoMap (CC-BY-SA)' }); var Esri_WorldImagery = L.tileLayer('https://server.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer/tile/{z}/{y}/{x}', { attribution: 'Tiles © Esri — Source: Esri, i-cubed, USDA, USGS, AEX, GeoEye, Getmapping, Aerogrid, IGN, IGP, UPR-EGP, and the GIS User Community' }); var Stamen_Toner = L.tileLayer('https://stamen-tiles-{s}.a.ssl.fastly.net/toner/{z}/{x}/{y}{r}.{ext}', { attribution: 'Map tiles by Stamen Design, CC BY 3.0 — Map data © OpenStreetMap contributors', subdomains: 'abcd', minZoom: 0, maxZoom: 20, ext: 'png' }); OpenStreetMap_Mapnik.addTo(map); var OpenStreetMap_Mapnik2 = L.tileLayer('https://tile.openstreetmap.org/{z}/{x}/{y}.png', { maxZoom: 19, attribution: '© OpenStreetMap contributors' }); var miniMap = new L.Control.MiniMap(OpenStreetMap_Mapnik2).addTo(map); var layerControl = L.control.layers({ "OSM": OpenStreetMap_Mapnik, "OSM Topo": OpenTopoMap, "ERSI Sat": Esri_WorldImagery, "Contrast": Stamen_Toner }, { Temperature: Temp, Precipitation: Precipitation, Clouds: Clouds, Pressure: Pressure, Wind: Wind }).addTo(map); var paintMode = false; var myPolyline; var dr = false; var loading = document.getElementById('placeholder'); socket.on('draw', function (msg) { var polyline = L.polyline(msg.line, {color: msg.color}).addTo(map); }); loading.innerHTML = "Loading history..."; socket.once('history', function (lines) { lines.forEach(line => { var polyline = L.polyline(line.line, {color: line.color}).addTo(map); }) loading.innerHTML = "History loaded..."; loading.style.display = 'none'; }); socket.on('color', function (user) { randomColor = user.color; myId = user.id; loading.innerHTML = "Color generated..."; }); /*var markers = L.layerGroup([]); markers.addTo(map); var myMakerIcon; L.edgeMarker({ icon: L.icon({ // style markers iconUrl: 'edge-arrow-marker-black.png', clickable: true, iconSize: [48, 48], iconAnchor: [24, 24] }), rotateIcons: true, layerGroup: markers }).addTo(map);*/ socket.on('users', function (users) { userDiv.innerHTML = ""; const currentUserIndex = users.findIndex(user => user.id === myId); if (currentUserIndex !== -1) { const currentUser = users.splice(currentUserIndex, 1)[0]; users.sort((a, b) => a.id - b.id); users.unshift(currentUser); } users.forEach((user, index) => { if (index === 0) { /*myMakerIcon = L.ExtraMarkers.icon({ //SET MY MARKER ICON icon: 'fa-number', svg: true, markerColor: randomColor, shape: 'circle', prefix: '' });*/ userDiv.innerHTML += 'You: '; userDiv.innerHTML += ``; // userDiv.innerHTML += `
`; userDiv.innerHTML += 'Others: '; } else { notyf.open({ type: 'info', message: 'User connected' }); userDiv.innerHTML += `
`; } }) loading.innerHTML = "Users ..."; }); /*socket.on('new_marker', function (marker) { var newMarker = L.marker([marker.coords.lat, marker.coords.lng], { draggable: true, autoPan: false, icon: L.ExtraMarkers.icon({ // style markers icon: 'fa-number', svg: true, markerColor: marker.color, shape: 'circle', prefix: '' }) }); newMarker.addTo(markers); // newMarker.on("dragend", function () { // socket.emit('new_marker', {"color": randomColor, "user": myId, "coords": newMarker.getLatLng()}); // }); });*/ var changedColor = false; userDiv.addEventListener('click', function (event) { if (event.target.id === 'you') { const userElement = event.target; userElement.addEventListener('input', colorChangeEvent => { const selectedColor = colorChangeEvent.target.value; randomColor = selectedColor; changedColor = true; }); } }); map.on('mousedown touchstart pointerdown', function (e) { if ('originalEvent' in e) { if (e.originalEvent.button === 1) { map.dragging.enable(); return; } } if (changedColor === true) { socket.emit('new_color', {"color": randomColor, "user": myId}); changedColor = false; } if (paintMode) { map.dragging.disable(); myPolyline = L.polyline([], {color: randomColor}).addTo(map); } dr = true; }); map.on('mouseup touchend pointerup touchleave', function (e) { dr = false; if (typeof myPolyline !== 'undefined' && null !== myPolyline) { socket.emit('draw', {"line": myPolyline.getLatLngs(), "user": myId}); } }) map.on('mousemove touchmove pointermove', function (e) { // console.log('mousemove') if (paintMode && dr) { if (e.type === 'touchmove' && e.originalEvent.touches.length > 1) { return; } myPolyline.addLatLng(e.latlng); } }) document.body.onkeyup = function (e) { if (e.key == " " || e.code == "Space" || e.keyCode == 32 ) { var container = document.getElementsByClassName('draw-paint')[0]; paintMode = !paintMode; if (paintMode) { container.style.backgroundColor = '#bfea90'; map.dragging.disable(); notyf.success("Paint Mode ENABLED"); } else { container.style.backgroundColor = 'white'; map.dragging.enable(); notyf.success("Paint Mode DISABLED"); } } } var drawPaint = L.Control.extend({ options: { position: 'topleft' }, onAdd: function (map) { var container = L.DomUtil.create('div', 'leaflet-bar leaflet-control leaflet-control-custom draw-paint'); container.style.backgroundColor = 'white'; container.style.backgroundImage = "url(https://assada.dead.guru/storage/images/image_2023_08_16_16_46_52.png)"; container.style.backgroundSize = "30px 30px"; container.style.width = '30px'; container.style.height = '30px'; container.setAttribute('title', "Toggle drawing"); container.onclick = function () { paintMode = !paintMode; if (paintMode) { map.dragging.disable(); container.style.backgroundColor = '#bfea90'; notyf.success("Paint Mode ENABLED"); } else { map.dragging.enable(); container.style.backgroundColor = 'white'; notyf.success("Paint Mode DISABLED"); } } return container; } }); /* var drawMarker = L.Control.extend({ options: { position: 'topleft' }, onAdd: function (map) { var container = L.DomUtil.create('div', 'leaflet-bar leaflet-control leaflet-control-custom draw-paint'); container.style.backgroundColor = 'white'; container.style.backgroundImage = "url(https://assada.dead.guru/storage/images/image_2023_08_16_16_46_52.png)"; container.style.backgroundSize = "30px 30px"; container.style.width = '30px'; container.style.height = '30px'; container.setAttribute('title', "Add marker"); container.onclick = function () { notyf.success("You can move marker by drag and drop"); var newMarker = L.marker(map.getCenter(), { draggable: true, autoPan: false, icon: myMakerIcon }); newMarker.addTo(markers); newMarker.on("dragend", function () { socket.emit('new_marker', {"color": randomColor, "user": myId, "coords": newMarker.getLatLng()}); }); socket.emit('new_marker', {"color": randomColor, "user": myId, "coords": newMarker.getLatLng()}); } return container; } });*/ map.addControl(new drawPaint()); // map.addControl(new drawMarker()); </script> </html>