Skip to content

Commit

Permalink
map location picker for devices
Browse files Browse the repository at this point in the history
  • Loading branch information
timcowlishaw committed Dec 18, 2024
1 parent 0942d7a commit 11f0cf3
Show file tree
Hide file tree
Showing 7 changed files with 107 additions and 2 deletions.
1 change: 1 addition & 0 deletions app/assets/stylesheets/application.scss
Original file line number Diff line number Diff line change
Expand Up @@ -25,3 +25,4 @@
@import "components/profile_header";
@import "components/copyable_input";
@import "components/device_map";
@import "components/map_location_picker";
4 changes: 4 additions & 0 deletions app/assets/stylesheets/components/map_location_picker.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
.map-location-picker {
width: 100%;
aspect-ratio: 1.66;
}
2 changes: 2 additions & 0 deletions app/javascript/application.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
import * as $ from "jquery";
import {setupCopyableInputs} from "components/copyable_input";
import {setupDeviceMaps} from "components/device_map";
import {setupMapLocationPickers} from "components/map_location_picker";

export default function setupApplication() {
$(function() {
setupCopyableInputs();
setupDeviceMaps();
setupMapLocationPickers();
});
}
2 changes: 1 addition & 1 deletion app/javascript/components/device_map.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ export function setupDeviceMaps() {
});
const map = L.map(element, {
center: [latitude, longitude],
zoom: 13,
zoom: 7,
attributionControl: false,
zoomControl: false,
scrollWheelZoom: false,
Expand Down
95 changes: 95 additions & 0 deletions app/javascript/components/map_location_picker.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
import * as $ from "jquery";
import L from 'leaflet';
import 'leaflet-defaulticon-compatibility';

const DEFAULT_LATITUDE = 41.396767038690285;
const DEFAULT_LONGITUDE = 2.1943382543588137;

class MapLocationPicker {
constructor(element) {
this.element = element
this.latitudeInput = $("#" + element.dataset["latitudeInputId"]);
this.longitudeInput = $("#" + element.dataset["longitudeInputId"]);
const markerUrl = element.dataset["markerUrl"];
const markerShadowUrl = element.dataset["markerShadowUrl"];
this.icon = L.icon({
iconUrl: markerUrl,
shadowUrl: markerShadowUrl,
iconSize: [32, 40],
shadowSize: [51, 59],
iconAnchor: [16, 40],
shadowAnchor: [10, 59]
});
this.map = L.map(this.element, {
center: this.defaultCenterLatLng(),
zoom: this.defaultZoom(),
attributionControl: false,
});
L.tileLayer('https://tiles.stadiamaps.com/tiles/stamen_toner/{z}/{x}/{y}{r}.{ext}', {
minZoom: 0,
maxZoom: 20,
attribution: '&copy; <a href="https://www.stadiamaps.com/" target="_blank">Stadia Maps</a> &copy; <a href="https://www.stamen.com/" target="_blank">Stamen Design</a> &copy; <a href="https://openmaptiles.org/" target="_blank">OpenMapTiles</a> &copy; <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors',
ext: 'png'
}).addTo(this.map);

if(this.getLatLng()) {
this.createMarker();
}

this.map.on('click', function(e) {
const latLng= e.latlng;
this.setLatLng(latLng.lat, latLng.lng);
if(this.marker) {
this.updateMarkerPosition();
} else {
this.createMarker();
}
}.bind(this));
}

defaultZoom() {
return this.getLatLng() ? 15 : 3;
}

defaultCenterLatLng() {
return this.getLatLng() || [DEFAULT_LATITUDE, DEFAULT_LONGITUDE]
}

getLatLng() {
const lat = this.latitudeInput.val();
const lng = this.longitudeInput.val();
if(lat && lng) {
return { "lat": lat, "lng": lng }
}
}

setLatLng(lat, lng) {
this.latitudeInput.val(lat);
this.longitudeInput.val(lng);
}

createMarker() {
const position = this.getLatLng();
this.marker = L.marker([position.lat, position.lng], { icon: this.icon, draggable: true }).addTo(this.map);
this.marker.on('dragend', function(event) {
var position = event.target.getLatLng();
this.setLatLng(position.lat, position.lng);
this.updateMarkerPosition();
}.bind(this));
this.map.panTo(new L.LatLng(position.lat, position.lng));
}

updateMarkerPosition() {
const position = this.getLatLng();
this.marker.setLatLng(new L.LatLng(position.lat, position.lng),{draggable:'true'});
this.map.panTo(new L.LatLng(position.lat, position.lng))
}
}



export function setupMapLocationPickers() {
$(".map-location-picker").each(function(ix, element) {
new MapLocationPicker(element);
});
}
4 changes: 3 additions & 1 deletion app/views/ui/devices/edit.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,9 @@
<div class="mt-5">
<h2 class="mb-0" ><%= t(:edit_device_location_subhead) %></h2>
<p class="mb-3"> <%= t(:edit_device_location_blurb) %></p>
<p style="color: red;"><strong>TODO</strong> implement map</p>
<%= f.hidden_field :latitude %>
<%= f.hidden_field :longitude %>
<%= render partial: "ui/shared/map_location_picker", locals: { latitude_input_id: "device_latitude", longitude_input_id: "device_longitude"} %>
</div>
<div class="mt-5">
<h2 class="mb-0"><%= t(:edit_device_open_data_subhead) %></h2>
Expand Down
1 change: 1 addition & 0 deletions app/views/ui/shared/_map_location_picker.html.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
<div class="map-location-picker" data-latitude-input-id="<%= latitude_input_id %>" data-longitude-input-id="<%= longitude_input_id %>" data-marker-url="<%= asset_url("map-pin.svg") %>" data-marker-shadow-url="<%= asset_url("map-pin-shadow.png") %>"></div>

0 comments on commit 11f0cf3

Please sign in to comment.