feat: remove geolocation logic from components
This commit is contained in:
parent
100d329d47
commit
622c436a9f
|
@ -24,22 +24,11 @@ const GoToTargetControl = L.Control.extend({
|
||||||
});
|
});
|
||||||
|
|
||||||
const GeolocationControl = L.Control.extend({
|
const GeolocationControl = L.Control.extend({
|
||||||
options: {
|
|
||||||
title: "Konum İzni Ver",
|
|
||||||
},
|
|
||||||
_watchingLocation: false,
|
|
||||||
_containerEl: null as HTMLButtonElement | null,
|
_containerEl: null as HTMLButtonElement | null,
|
||||||
_currentLocationMarker: null as L.Marker | null,
|
_currentLocationMarker: null as L.Marker | null,
|
||||||
setCurrentLocationMarker: function (marker?: L.Marker) {
|
setCurrentLocationMarker: function (marker?: L.Marker) {
|
||||||
if (marker) this._currentLocationMarker = marker;
|
if (marker) this._currentLocationMarker = marker;
|
||||||
},
|
},
|
||||||
initialize: function (options: any) {
|
|
||||||
L.Util.setOptions(this, options);
|
|
||||||
},
|
|
||||||
startWatching: function () {
|
|
||||||
this._watchingLocation = true;
|
|
||||||
if (this._containerEl) this._containerEl.textContent = "Konumuma Git";
|
|
||||||
},
|
|
||||||
onAdd: function (map: L.Map) {
|
onAdd: function (map: L.Map) {
|
||||||
const locationButton = document.createElement("button");
|
const locationButton = document.createElement("button");
|
||||||
|
|
||||||
|
@ -47,17 +36,15 @@ const GeolocationControl = L.Control.extend({
|
||||||
|
|
||||||
locationButton.id = "ask-permission-control-button";
|
locationButton.id = "ask-permission-control-button";
|
||||||
|
|
||||||
locationButton.textContent = this.options.title;
|
locationButton.textContent = "Konumuma Git";
|
||||||
|
|
||||||
locationButton.classList.add("custom-map-control-button");
|
locationButton.classList.add("custom-map-control-button");
|
||||||
|
|
||||||
locationButton.type = "button";
|
locationButton.type = "button";
|
||||||
|
|
||||||
L.DomEvent.on(locationButton, "click", () => {
|
L.DomEvent.on(locationButton, "click", () => {
|
||||||
if (this._watchingLocation && this._currentLocationMarker) {
|
if (this._currentLocationMarker) {
|
||||||
map.setView(this._currentLocationMarker.getLatLng(), 12);
|
map.setView(this._currentLocationMarker.getLatLng(), 12);
|
||||||
} else {
|
|
||||||
this.startWatching();
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -40,19 +40,14 @@ function errorCallback(err: GeolocationPositionError) {
|
||||||
}
|
}
|
||||||
|
|
||||||
function calculateDistance(
|
function calculateDistance(
|
||||||
currentPosition: GeolocationPosition,
|
currentPosition: L.LatLngTuple,
|
||||||
targetPosition: L.LatLngTuple
|
targetPosition: L.LatLngTuple
|
||||||
) {
|
) {
|
||||||
const pos = {
|
|
||||||
lat: currentPosition.coords.latitude,
|
|
||||||
lng: currentPosition.coords.longitude,
|
|
||||||
};
|
|
||||||
|
|
||||||
// Get target position in latitudes and longitudes
|
// Get target position in latitudes and longitudes
|
||||||
const targetLatLng = L.latLng(targetPosition);
|
const targetLatLng = L.latLng(targetPosition);
|
||||||
|
|
||||||
// Get current position in latitudes and longitudes
|
// Get current position in latitudes and longitudes
|
||||||
const currentLatLng = L.latLng(pos);
|
const currentLatLng = L.latLng(currentPosition);
|
||||||
|
|
||||||
// Calculate the distance between target and current position in meters
|
// Calculate the distance between target and current position in meters
|
||||||
const betweenMeters = currentLatLng.distanceTo(targetLatLng);
|
const betweenMeters = currentLatLng.distanceTo(targetLatLng);
|
||||||
|
|
|
@ -1,5 +1,11 @@
|
||||||
// Lit
|
// Lit
|
||||||
import { html, LitElement, unsafeCSS, type CSSResultGroup } from "lit";
|
import {
|
||||||
|
html,
|
||||||
|
LitElement,
|
||||||
|
unsafeCSS,
|
||||||
|
type CSSResultGroup,
|
||||||
|
type PropertyValues,
|
||||||
|
} from "lit";
|
||||||
import { customElement, property, query, state } from "lit/decorators.js";
|
import { customElement, property, query, state } from "lit/decorators.js";
|
||||||
|
|
||||||
// Leaflet
|
// Leaflet
|
||||||
|
@ -12,7 +18,6 @@ import { GeolocationControl, GoToTargetControl } from "./LeafletMap/controls";
|
||||||
import leafletStyles from "leaflet/dist/leaflet.css?inline";
|
import leafletStyles from "leaflet/dist/leaflet.css?inline";
|
||||||
import globalStyles from "@/styles/globals.css?inline";
|
import globalStyles from "@/styles/globals.css?inline";
|
||||||
import mapStyles from "@/styles/locked-page.css?inline";
|
import mapStyles from "@/styles/locked-page.css?inline";
|
||||||
import { onLocationError, onLocationSuccess } from "./LeafletMap/geolocation";
|
|
||||||
|
|
||||||
@customElement("leaflet-map")
|
@customElement("leaflet-map")
|
||||||
export class LeafletMap extends LitElement {
|
export class LeafletMap extends LitElement {
|
||||||
|
@ -34,27 +39,19 @@ export class LeafletMap extends LitElement {
|
||||||
_askPermissionButton!: HTMLButtonElement;
|
_askPermissionButton!: HTMLButtonElement;
|
||||||
|
|
||||||
// Properties and states
|
// Properties and states
|
||||||
@property({ type: Object }) targetLocation?: LatLngTuple;
|
@property({ type: Object, noAccessor: true }) targetLocation?: LatLngTuple;
|
||||||
|
@property({ type: Object })
|
||||||
|
currentPosition?: LatLngTuple;
|
||||||
|
|
||||||
@state()
|
@state()
|
||||||
protected _map?: L.Map;
|
protected _map?: L.Map;
|
||||||
@state()
|
@state()
|
||||||
protected _geolocationPermissionStatus: PermissionState = "prompt";
|
|
||||||
@state()
|
|
||||||
protected _currentLocationMarker?: L.Marker;
|
protected _currentLocationMarker?: L.Marker;
|
||||||
@state()
|
|
||||||
protected _watchingLocation = false;
|
|
||||||
|
|
||||||
firstUpdated(): void {
|
firstUpdated(): void {
|
||||||
if (!this._mapElement || !this.targetLocation) return;
|
if (!this._mapElement || !this.targetLocation) return;
|
||||||
this._map = new Map(this._mapElement).setView(this.targetLocation, 13);
|
this._map = new Map(this._mapElement).setView(this.targetLocation, 13);
|
||||||
|
|
||||||
this._map.on("locationerror", onLocationError);
|
|
||||||
|
|
||||||
this._map.on("locationfound", (ev) =>
|
|
||||||
onLocationSuccess(ev, this._map!, this._currentLocationMarker)
|
|
||||||
);
|
|
||||||
|
|
||||||
L.tileLayer("https://tile.openstreetmap.org/{z}/{x}/{y}.png", {
|
L.tileLayer("https://tile.openstreetmap.org/{z}/{x}/{y}.png", {
|
||||||
maxZoom: 19,
|
maxZoom: 19,
|
||||||
attribution:
|
attribution:
|
||||||
|
@ -81,38 +78,21 @@ export class LeafletMap extends LitElement {
|
||||||
targetLocationControl.setTargetLocation(this.targetLocation);
|
targetLocationControl.setTargetLocation(this.targetLocation);
|
||||||
targetLocationControl.addTo(this._map);
|
targetLocationControl.addTo(this._map);
|
||||||
|
|
||||||
// Check geolocation permission, if user has given permission before
|
const currentLocationControl = new GeolocationControl({
|
||||||
// start watching user location
|
position: "bottomleft",
|
||||||
navigator.permissions
|
});
|
||||||
.query({ name: "geolocation" })
|
|
||||||
.then((permissionStatus) => {
|
|
||||||
switch (permissionStatus.state) {
|
|
||||||
case "granted":
|
|
||||||
this._geolocationPermissionStatus = "granted";
|
|
||||||
const locateUserControl = new GeolocationControl({
|
|
||||||
// @ts-expect-error
|
|
||||||
title: "Konumuma Git",
|
|
||||||
position: "bottomleft",
|
|
||||||
});
|
|
||||||
locateUserControl.setCurrentLocationMarker(
|
|
||||||
this._currentLocationMarker
|
|
||||||
);
|
|
||||||
locateUserControl.addTo(this._map!);
|
|
||||||
break;
|
|
||||||
case "denied":
|
|
||||||
this._geolocationPermissionStatus = "denied";
|
|
||||||
break;
|
|
||||||
case "prompt":
|
|
||||||
const askPermissionControl = new GeolocationControl({
|
|
||||||
position: "bottomleft",
|
|
||||||
});
|
|
||||||
|
|
||||||
askPermissionControl.addTo(this._map!);
|
currentLocationControl.setCurrentLocationMarker(
|
||||||
break;
|
this._currentLocationMarker
|
||||||
default:
|
);
|
||||||
break;
|
currentLocationControl.addTo(this._map);
|
||||||
}
|
}
|
||||||
});
|
|
||||||
|
protected update(changedProperties: PropertyValues): void {
|
||||||
|
super.update(changedProperties);
|
||||||
|
if (changedProperties.get("currentPosition")) {
|
||||||
|
this._currentLocationMarker?.setLatLng(this.currentPosition!);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
|
|
|
@ -18,7 +18,7 @@ import {
|
||||||
} from "./LockedContent/templates";
|
} from "./LockedContent/templates";
|
||||||
|
|
||||||
// Geolocation utils
|
// Geolocation utils
|
||||||
import { calculateDistance, errorCallback } from "./LockedContent/geolocation";
|
import { calculateDistance } from "./LockedContent/geolocation";
|
||||||
import { incrementUnlockCounter } from "./LockedContent/serverUtils";
|
import { incrementUnlockCounter } from "./LockedContent/serverUtils";
|
||||||
|
|
||||||
// LockedContent is a custom element watching user location and blurring
|
// LockedContent is a custom element watching user location and blurring
|
||||||
|
@ -44,35 +44,16 @@ export class LockedContent extends LitElement {
|
||||||
@property({ noAccessor: true }) readonly imageURL?: string;
|
@property({ noAccessor: true }) readonly imageURL?: string;
|
||||||
@property({ type: Object, noAccessor: true })
|
@property({ type: Object, noAccessor: true })
|
||||||
readonly targetPosition?: LatLngTuple;
|
readonly targetPosition?: LatLngTuple;
|
||||||
|
@property({ type: Object })
|
||||||
|
currentPosition?: LatLngTuple;
|
||||||
|
|
||||||
// Reactive states, template is rendered according to this states
|
// Reactive states, template is rendered according to this states
|
||||||
@state()
|
@state()
|
||||||
protected _geolocationPermissionStatus: PermissionState = "prompt";
|
|
||||||
@state()
|
|
||||||
protected _unlocked = false;
|
protected _unlocked = false;
|
||||||
@state()
|
@state()
|
||||||
protected _arrived = false;
|
protected _arrived = false;
|
||||||
@state()
|
@state()
|
||||||
protected _distanceText?: string;
|
protected _distanceText?: string;
|
||||||
@state()
|
|
||||||
protected _watchId?: number;
|
|
||||||
|
|
||||||
// This callback will be fired when geolocation info is available
|
|
||||||
successCallback(position: GeolocationPosition) {
|
|
||||||
// Set hasGeolocationPermission state true to change the template
|
|
||||||
this._geolocationPermissionStatus = "granted";
|
|
||||||
|
|
||||||
// Target position must be set
|
|
||||||
if (!this.targetPosition) return;
|
|
||||||
|
|
||||||
// Calculate the distance between target and current position in meters
|
|
||||||
const distance = calculateDistance(position, this.targetPosition);
|
|
||||||
|
|
||||||
// Update the text based on the distance
|
|
||||||
this._updateDistanceText(distance);
|
|
||||||
|
|
||||||
this._checkArrived(distance);
|
|
||||||
}
|
|
||||||
|
|
||||||
private _updateDistanceText(distance: number) {
|
private _updateDistanceText(distance: number) {
|
||||||
// Update the proximity text according to the distance remaining
|
// Update the proximity text according to the distance remaining
|
||||||
|
@ -86,10 +67,6 @@ export class LockedContent extends LitElement {
|
||||||
private _checkArrived(distance: number) {
|
private _checkArrived(distance: number) {
|
||||||
// If target is close less then 100 meters user has arrived to target location
|
// If target is close less then 100 meters user has arrived to target location
|
||||||
if (distance < 100) {
|
if (distance < 100) {
|
||||||
if (this._watchId) {
|
|
||||||
// Stop watching location
|
|
||||||
navigator.geolocation.clearWatch(this._watchId);
|
|
||||||
}
|
|
||||||
// Update state to reveal the image
|
// Update state to reveal the image
|
||||||
this._arrived = true;
|
this._arrived = true;
|
||||||
}
|
}
|
||||||
|
@ -98,11 +75,26 @@ export class LockedContent extends LitElement {
|
||||||
// This template is shown when user hasn't give geolocation permission yet
|
// This template is shown when user hasn't give geolocation permission yet
|
||||||
// When user click the button user is asked for geolocation permission
|
// When user click the button user is asked for geolocation permission
|
||||||
private _permissionButtonTemplate = () =>
|
private _permissionButtonTemplate = () =>
|
||||||
permissionButtonTemplate(this._startWatchingLocation);
|
permissionButtonTemplate(() => null);
|
||||||
|
|
||||||
// This template is shown when user has given permission but has not arrived yet
|
// This template is shown when user has given permission but has not arrived yet
|
||||||
private _lockedButtonTemplate = () =>
|
private _lockedButtonTemplate = () => {
|
||||||
lockedButtonTemplate(this._distanceText);
|
// Target position must be set
|
||||||
|
if (!this.targetPosition || !this.currentPosition) return;
|
||||||
|
|
||||||
|
// Calculate the distance between target and current position in meters
|
||||||
|
const distance = calculateDistance(
|
||||||
|
this.currentPosition,
|
||||||
|
this.targetPosition
|
||||||
|
);
|
||||||
|
|
||||||
|
// Update the text based on the distance
|
||||||
|
this._updateDistanceText(distance);
|
||||||
|
|
||||||
|
this._checkArrived(distance);
|
||||||
|
|
||||||
|
return lockedButtonTemplate(this._distanceText);
|
||||||
|
};
|
||||||
|
|
||||||
// This template is shown when user has arrived to the target location
|
// This template is shown when user has arrived to the target location
|
||||||
// When user click the button counter at the bottom of the page is incremented
|
// When user click the button counter at the bottom of the page is incremented
|
||||||
|
@ -113,46 +105,8 @@ export class LockedContent extends LitElement {
|
||||||
this._unlocked = true;
|
this._unlocked = true;
|
||||||
});
|
});
|
||||||
|
|
||||||
// Start watching user location, if user has not given permission yet
|
|
||||||
// this will ask the user for permission and update the watch id
|
|
||||||
private _startWatchingLocation() {
|
|
||||||
// User is already being watched no need to
|
|
||||||
// watch position
|
|
||||||
if (this._watchId) return;
|
|
||||||
|
|
||||||
const id = navigator.geolocation.watchPosition(
|
|
||||||
this.successCallback.bind(this),
|
|
||||||
(err) => {
|
|
||||||
if (err.code == GeolocationPositionError.PERMISSION_DENIED) {
|
|
||||||
this._geolocationPermissionStatus = "denied";
|
|
||||||
}
|
|
||||||
errorCallback(err);
|
|
||||||
},
|
|
||||||
this.geolocationOptions
|
|
||||||
);
|
|
||||||
|
|
||||||
this._watchId = id;
|
|
||||||
}
|
|
||||||
|
|
||||||
connectedCallback(): void {
|
connectedCallback(): void {
|
||||||
super.connectedCallback();
|
super.connectedCallback();
|
||||||
|
|
||||||
// Check geolocation permission, if user has given permission before
|
|
||||||
// start watching user location
|
|
||||||
navigator.permissions
|
|
||||||
.query({ name: "geolocation" })
|
|
||||||
.then((permissionStatus) => {
|
|
||||||
switch (permissionStatus.state) {
|
|
||||||
case "granted":
|
|
||||||
this._startWatchingLocation();
|
|
||||||
break;
|
|
||||||
case "denied":
|
|
||||||
this._geolocationPermissionStatus = "denied";
|
|
||||||
case "prompt":
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
|
@ -165,9 +119,9 @@ export class LockedContent extends LitElement {
|
||||||
// 4 - User did not give geolocation permission
|
// 4 - User did not give geolocation permission
|
||||||
if (this._arrived) {
|
if (this._arrived) {
|
||||||
buttonTemplate = this._unlockedButtonTemplate;
|
buttonTemplate = this._unlockedButtonTemplate;
|
||||||
} else if (this._geolocationPermissionStatus == "granted") {
|
} else if (this.currentPosition) {
|
||||||
buttonTemplate = this._lockedButtonTemplate;
|
buttonTemplate = this._lockedButtonTemplate;
|
||||||
} else if (this._geolocationPermissionStatus == "prompt") {
|
} else if (!this.currentPosition) {
|
||||||
buttonTemplate = this._permissionButtonTemplate;
|
buttonTemplate = this._permissionButtonTemplate;
|
||||||
} else {
|
} else {
|
||||||
buttonTemplate = permissionDeniedButtonTemplate;
|
buttonTemplate = permissionDeniedButtonTemplate;
|
||||||
|
|
Loading…
Reference in New Issue
Block a user