Get registration location map working with OSM

This commit is contained in:
Cillian O'Ruanaidh
2024-05-17 14:53:47 +01:00
committed by zanetagebka
parent f4a69b4664
commit 87fe5f413b
8 changed files with 166 additions and 3 deletions

View File

@@ -42,8 +42,17 @@ angular.module('Darkswarm').controller "RegistrationCtrl", ($scope, Registration
$scope.toggleAddressConfirmed = ->
$scope.addressConfirmed = !$scope.addressConfirmed
if $scope.addressConfirmed
$scope.setLatLongIfUsingOpenStreetMap()
$scope.enterprise.address.latitude = $scope.latLong.latitude
$scope.enterprise.address.longitude = $scope.latLong.longitude
else
$scope.enterprise.address.latitude = null
$scope.enterprise.address.longitude = null
# When OpenStreetMaps is enabled the latitude and longitude are calculated via a Stimulus
# controller, so they need to be read from data properties to be accessible here.
$scope.setLatLongIfUsingOpenStreetMap = ->
openStreetMap = document.getElementById("open-street-map")
if !$scope.latLong && openStreetMap && openStreetMap.dataset.latitude && openStreetMap.dataset.longitude
$scope.latLong = { latitude: openStreetMap.dataset.latitude, longitude: openStreetMap.dataset.longitude }

View File

@@ -2,7 +2,9 @@
module MapHelper
def using_google_maps?
ENV["GOOGLE_MAPS_API_KEY"].present? || google_maps_configured_with_geocoder_api_key?
!ContentConfig.open_street_map_enabled && (
ENV["GOOGLE_MAPS_API_KEY"].present? || google_maps_configured_with_geocoder_api_key?
)
end
private

View File

@@ -57,7 +57,10 @@
%span.error{ "ng-show": "details.state.$error.required && submitted" }
= t(".state_field_error")
= render 'registration/steps/location_map' if using_google_maps?
- if using_google_maps?
= render 'registration/steps/location_map_google'
- elsif ContentConfig.open_street_map_enabled
= render 'registration/steps/location_map_osm'
.row.buttons
.small-12.columns

View File

@@ -0,0 +1,18 @@
%div{ data: {
controller: "open-street-map",
"open-street-map-default-latitude-value": ContentConfig.open_street_map_default_latitude,
"open-street-map-default-longitude-value": ContentConfig.open_street_map_default_longitude,
"open-street-map-provider-name-value": ContentConfig.open_street_map_provider_name,
"open-street-map-provider-options-value": ContentConfig.open_street_map_provider_options
}
}
.center
%input.button.primary{ data: { action: "click->open-street-map#locateAddress" }, type: "button", value: "{{'registration.steps.details.locate_address' | t}}" }
.center{ data: { "open-street-map-target": "dragPinNote" }, style: "display: none" }
%strong {{'registration.steps.details.drag_pin' | t}}
#open-street-map.map-container--registration
.center{ data: { "open-street-map-target": "confirmAddressField" }, style: "display: none" }
.field
%input{ type: 'checkbox', id: 'confirm_address', name: 'confirm_address', "ng-click": 'toggleAddressConfirmed()' }
%label{ for: 'confirm_address' } {{'registration.steps.details.confirm_address' | t}}

View File

@@ -0,0 +1,103 @@
import { Controller } from "stimulus";
import L from "leaflet";
import LeafetProviders from "leaflet-providers";
import { OpenStreetMapProvider } from 'leaflet-geosearch';
export default class extends Controller {
static targets = ["confirmAddressField", "dragPinNote"];
static values = {
defaultLatitude: Number,
defaultLongitude: Number,
providerName: String,
providerOptions: Object
};
connect() {
this.zoomLevel = 6;
this.#displayMapWhenAtRegistrationDetailsStep();
}
disconnect() {
this.map.remove();
}
async locateAddress() {
const results = await this.provider.search({ query: this.#addressQuery() });
if(results.length > 0) {
const result = results[0];
this.#setLatitudeLongitude(result.y, result.x);
this.#addMarker(result.y, result.x);
this.map.setView([result.y, result.x], this.zoomLevel);
this.confirmAddressFieldTarget.style.display = "block";
this.dragPinNoteTarget.style.display = "block";
}
}
#addressQuery() {
const stateField = document.getElementById("enterprise_state");
const state = stateField.options[stateField.selectedIndex]?.label;
const countryField = document.getElementById("enterprise_country");
const country = countryField.options[countryField.selectedIndex]?.label;
const city = document.getElementById("enterprise_city")?.value;
const zipcode = document.getElementById("enterprise_zipcode")?.value;
const addressLine1 = document.getElementById("enterprise_address")?.value;
const addressLine2 = document.getElementById("enterprise_address2")?.value;
// If someone clicks the locate address on map button without filling in their address the
// geocoded address will not be very accurate so don't zoom in too close so it's easier for
// people to see where the marker is.
if(!addressLine1 && !city && !zipcode) {
this.zoomLevel = 6;
} else {
this.zoomLevel = 14;
}
return [addressLine1, addressLine2, city, state, zipcode, country].filter((value) => !!value).join(", ")
}
#addMarker(latitude, longitude) {
const icon = L.icon({ iconUrl: "/map_icons/map_003-producer-shop.svg" });
this.marker = L.marker([latitude, longitude], {
draggable: true,
icon: icon,
});
this.marker.on("dragend", (event) => {
const position = event.target.getLatLng();
this.#setLatitudeLongitude(position.lat, position.lng);
});
this.marker.addTo(this.map);
}
#displayMap() {
this.map = L.map('open-street-map')
L.tileLayer.provider(this.providerNameValue, this.providerOptionsValue).addTo(this.map)
this.map.setView([this.defaultLatitudeValue, this.defaultLongitudeValue], this.zoomLevel)
this.provider = new OpenStreetMapProvider();
}
// The connect() method is called before the registration details step is visible, this
// causes the map tiles to render incorrectly. To fix this only display the map when the
// registration details step has been reached.
#displayMapWhenAtRegistrationDetailsStep() {
const observer = new IntersectionObserver(
([intersectionObserverEntry]) => {
if(intersectionObserverEntry.target.offsetParent !== null) {
this.#displayMap();
observer.disconnect()
}
},
{ threshold: [0] }
);
observer.observe(document.getElementById("registration-details"));
}
// The registration process uses Angular, set latitude and longitude data properties so the
// Angular RegistrationCtrl controller can read and add them to the parameters it uses to create
// new enterprises.
#setLatitudeLongitude(latitude, longitude) {
document.getElementById("open-street-map").dataset.latitude = latitude;
document.getElementById("open-street-map").dataset.longitude = longitude;
}
}

View File

@@ -22,6 +22,9 @@
"hotkeys-js": "^3.13.7",
"jquery-ui": "1.13.3",
"js-big-decimal": "^2.0.7",
"leaflet": "1.9.4",
"leaflet-geosearch": "3.11.1",
"leaflet-providers": "2.0.0",
"moment": "^2.30.1",
"mrujs": "^1.0.0",
"select2": "^4.0.13",

View File

@@ -1112,6 +1112,13 @@
resolved "https://registry.yarnpkg.com/@floating-ui/utils/-/utils-0.2.1.tgz#16308cea045f0fc777b6ff20a9f25474dd8293d2"
integrity sha512-9TANp6GPoMtYzQdt54kfAyMmz1+osLlXdg2ENroU7zzrtflTLrrC/lgrIfaSe+Wu0b89GKccT7vxXA0MoAIO+Q==
"@googlemaps/js-api-loader@^1.16.6":
version "1.16.6"
resolved "https://registry.yarnpkg.com/@googlemaps/js-api-loader/-/js-api-loader-1.16.6.tgz#c89970c94b55796d51746c092f0e52953994a171"
integrity sha512-V8p5W9DbPQx74jWUmyYJOerhiB4C+MHekaO0ZRmc6lrOYrvY7+syLhzOWpp55kqSPeNb+qbC2h8i69aLIX6krQ==
dependencies:
fast-deep-equal "^3.1.3"
"@hotwired/stimulus-webpack-helpers@^1.0.0":
version "1.0.1"
resolved "https://registry.yarnpkg.com/@hotwired/stimulus-webpack-helpers/-/stimulus-webpack-helpers-1.0.1.tgz#4cd74487adeca576c9865ac2b9fe5cb20cef16dd"
@@ -3911,7 +3918,7 @@ extglob@^2.0.4:
snapdragon "^0.8.1"
to-regex "^3.0.1"
fast-deep-equal@^3.1.1:
fast-deep-equal@^3.1.1, fast-deep-equal@^3.1.3:
version "3.1.3"
resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525"
integrity sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==
@@ -5707,6 +5714,24 @@ last-call-webpack-plugin@^3.0.0:
lodash "^4.17.5"
webpack-sources "^1.1.0"
leaflet-geosearch@3.11.1:
version "3.11.1"
resolved "https://registry.yarnpkg.com/leaflet-geosearch/-/leaflet-geosearch-3.11.1.tgz#e35b1e156afef388bbb42543eb56502e9a633192"
integrity sha512-cILLFLmn8C3MtGhaafGqY7CuhUG2+bGyUgfPHgNgW6fs4EvYyiIO88nO2ZqR7Hy6Ba089haLkhODpZR+/fRrPQ==
optionalDependencies:
"@googlemaps/js-api-loader" "^1.16.6"
leaflet "^1.6.0"
leaflet-providers@2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/leaflet-providers/-/leaflet-providers-2.0.0.tgz#dfdab9ca2dccc57c79e1462bc3dd20f78910afcb"
integrity sha512-CWwKEnHd66Qsx0m4o5q5ZOa60s00B91pMxnlr4Y22msubfs7dhbZhdMIz8bvZQkrZqi67ppI1fsZRS6vtrLcOA==
leaflet@1.9.4, leaflet@^1.6.0:
version "1.9.4"
resolved "https://registry.yarnpkg.com/leaflet/-/leaflet-1.9.4.tgz#23fae724e282fa25745aff82ca4d394748db7d8d"
integrity sha512-nxS1ynzJOmOlHp+iL3FyWqK89GtNL8U8rvlMOsQdTTssxZwCXh8N2NB3GDQOL+YR3XnWyZAxwQixURb+FA74PA==
leven@^3.1.0:
version "3.1.0"
resolved "https://registry.yarnpkg.com/leven/-/leven-3.1.0.tgz#77891de834064cccba82ae7842bb6b14a13ed7f2"