You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
282 lines
7.7 KiB
282 lines
7.7 KiB
1 year ago
|
<template>
|
||
|
<!-- CONTENT -->
|
||
|
<section id="Content" class="p-6 pb-24">
|
||
|
<!-- Breadcrumb -->
|
||
|
<div class="mb-8">
|
||
|
<!-- Back -->
|
||
|
<div class="text-lg text-center font-light relative px-7">
|
||
|
<h1
|
||
|
class="text-lg text-center px-2 py-1 absolute -left-2 -top-1"
|
||
|
@click="$router.back()"
|
||
|
>
|
||
|
<fa icon="chevron-left" class="fa-fw"></fa>
|
||
|
</h1>
|
||
|
</div>
|
||
|
|
||
|
<!-- Heading -->
|
||
|
<h1 id="ViewHeading" class="text-4xl text-center font-light pt-4 mb-8">
|
||
|
Area for Nearby Search
|
||
|
</h1>
|
||
|
</div>
|
||
|
|
||
|
<div class="px-2 py-4">
|
||
|
This location is only stored on your device. It is used to show you more
|
||
|
appropriate projects but is not stored on any servers.
|
||
|
</div>
|
||
|
|
||
|
<div>
|
||
|
<button v-if="!searchBox && !isNewMarkerSet" class="m-4 px-4 py-2">
|
||
|
Click to Choose a Location for Nearby Search
|
||
|
</button>
|
||
|
<button
|
||
|
v-if="isNewMarkerSet"
|
||
|
class="m-4 px-4 py-2 rounded-md bg-blue-200 text-blue-500"
|
||
|
@click="storeSearchBox"
|
||
|
>
|
||
|
Store This Location for Nearby Search
|
||
|
</button>
|
||
|
<button
|
||
|
v-if="searchBox"
|
||
|
class="m-4 px-4 py-2 rounded-md bg-blue-200 text-blue-500"
|
||
|
@click="forgetSearchBox"
|
||
|
>
|
||
|
Delete Stored Location
|
||
|
</button>
|
||
|
<button
|
||
|
v-if="searchBox"
|
||
|
class="m-4 px-4 py-2 rounded-md bg-blue-200 text-blue-500"
|
||
|
@click="resetLatLong"
|
||
|
>
|
||
|
Reset Marker
|
||
|
</button>
|
||
|
<button
|
||
|
v-if="isNewMarkerSet"
|
||
|
class="m-4 px-4 py-2 rounded-md bg-blue-200 text-blue-500"
|
||
|
@click="isNewMarkerSet = false"
|
||
|
>
|
||
|
Erase Marker
|
||
|
</button>
|
||
|
<div v-if="isNewMarkerSet">
|
||
|
Click on the pin to erase it. Click anywhere else to set a different
|
||
|
different corner.
|
||
|
</div>
|
||
|
</div>
|
||
|
|
||
|
<div style="height: 600px; width: 800px">
|
||
|
<l-map
|
||
|
ref="map"
|
||
|
:center="[localCenterLat, localCenterLong]"
|
||
|
v-model:zoom="localZoom"
|
||
|
@click="setMapPoint"
|
||
|
>
|
||
|
<l-tile-layer
|
||
|
url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"
|
||
|
layer-type="base"
|
||
|
name="OpenStreetMap"
|
||
|
/>
|
||
|
<l-marker
|
||
|
v-if="isNewMarkerSet"
|
||
|
:lat-lng="[localCenterLat, localCenterLong]"
|
||
|
@click="isNewMarkerSet = false"
|
||
|
/>
|
||
|
<l-rectangle
|
||
|
v-if="isNewMarkerSet"
|
||
|
:bounds="[
|
||
|
[localCenterLat - localLatDiff, localCenterLong - localLongDiff],
|
||
|
[localCenterLat + localLatDiff, localCenterLong + localLongDiff],
|
||
|
]"
|
||
|
:weight="1"
|
||
|
/>
|
||
|
</l-map>
|
||
|
</div>
|
||
|
</section>
|
||
|
</template>
|
||
|
|
||
|
<script lang="ts">
|
||
|
import { LeafletMouseEvent } from "leaflet";
|
||
|
import "leaflet/dist/leaflet.css";
|
||
|
import { Component, Vue } from "vue-facing-decorator";
|
||
|
import {
|
||
|
LMap,
|
||
|
LMarker,
|
||
|
LRectangle,
|
||
|
LTileLayer,
|
||
|
} from "@vue-leaflet/vue-leaflet";
|
||
|
|
||
|
import { db } from "@/db/index";
|
||
|
import { BoundingBox, MASTER_SETTINGS_KEY } from "@/db/tables/settings";
|
||
|
|
||
|
const DEFAULT_LAT_LONG_DIFF = 0.01;
|
||
|
const WORLD_ZOOM = 2;
|
||
|
const DEFAULT_ZOOM = 2;
|
||
|
|
||
|
interface Notification {
|
||
|
group: string;
|
||
|
type: string;
|
||
|
title: string;
|
||
|
text: string;
|
||
|
}
|
||
|
|
||
|
@Component({
|
||
|
components: {
|
||
|
LRectangle,
|
||
|
LMap,
|
||
|
LMarker,
|
||
|
LTileLayer,
|
||
|
},
|
||
|
})
|
||
|
export default class DiscoverView extends Vue {
|
||
|
$notify!: (notification: Notification, timeout?: number) => void;
|
||
|
|
||
|
isChoosingSearchBox = false;
|
||
|
isNewMarkerSet = false;
|
||
|
|
||
|
// "local" vars are for the currently selected map box
|
||
|
localCenterLat = 0;
|
||
|
localCenterLong = 0;
|
||
|
localLatDiff = DEFAULT_LAT_LONG_DIFF;
|
||
|
localLongDiff = DEFAULT_LAT_LONG_DIFF;
|
||
|
localZoom = DEFAULT_ZOOM;
|
||
|
|
||
|
// searchBox reflects what is stored in the database
|
||
|
searchBox: { name: string; bbox: BoundingBox } | null = null;
|
||
|
|
||
|
async mounted() {
|
||
|
await db.open();
|
||
|
const settings = await db.settings.get(MASTER_SETTINGS_KEY);
|
||
|
this.searchBox = settings?.searchBoxes?.[0] || null;
|
||
|
this.resetLatLong();
|
||
|
}
|
||
|
|
||
|
setMapPoint(event: LeafletMouseEvent) {
|
||
|
if (this.isNewMarkerSet) {
|
||
|
this.localLatDiff = Math.abs(event.latlng.lat - this.localCenterLat);
|
||
|
this.localLongDiff = Math.abs(event.latlng.lng - this.localCenterLong);
|
||
|
} else {
|
||
|
// marker is not set
|
||
|
this.localCenterLat = event.latlng.lat;
|
||
|
this.localCenterLong = event.latlng.lng;
|
||
|
|
||
|
let latDiff = DEFAULT_LAT_LONG_DIFF;
|
||
|
let longDiff = DEFAULT_LAT_LONG_DIFF;
|
||
|
// Guess at a size for the bounding box.
|
||
|
// This doesn't seem like the right approach but it's the only way I can find to get the screen bounds.
|
||
|
const bounds = event.target.boxZoom?._map?.getBounds();
|
||
|
if (bounds) {
|
||
|
latDiff = Math.abs(bounds._northEast.lat - bounds._southWest.lat) / 8;
|
||
|
longDiff = Math.abs(bounds._northEast.lng - bounds._southWest.lng) / 8;
|
||
|
}
|
||
|
this.localLatDiff = latDiff;
|
||
|
this.localLongDiff = longDiff;
|
||
|
this.isNewMarkerSet = true;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public resetLatLong() {
|
||
|
if (this.searchBox?.bbox) {
|
||
|
const bbox = this.searchBox.bbox;
|
||
|
this.localCenterLat = (bbox.maxLat + bbox.minLat) / 2;
|
||
|
this.localCenterLong = (bbox.eastLong + bbox.westLong) / 2;
|
||
|
this.localLatDiff = (bbox.maxLat - bbox.minLat) / 2;
|
||
|
this.localLongDiff = (bbox.eastLong - bbox.westLong) / 2;
|
||
|
this.localZoom = WORLD_ZOOM;
|
||
|
this.isNewMarkerSet = true;
|
||
|
} else {
|
||
|
this.isNewMarkerSet = false;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public async storeSearchBox() {
|
||
|
if (this.localCenterLong || this.localCenterLat) {
|
||
|
try {
|
||
|
const newSearchBox = {
|
||
|
name: "Local",
|
||
|
bbox: {
|
||
|
eastLong: this.localCenterLong + this.localLongDiff,
|
||
|
maxLat: this.localCenterLat + this.localLatDiff,
|
||
|
minLat: this.localCenterLat - this.localLatDiff,
|
||
|
westLong: this.localCenterLong - this.localLongDiff,
|
||
|
},
|
||
|
};
|
||
|
await db.open();
|
||
|
db.settings.update(MASTER_SETTINGS_KEY, {
|
||
|
searchBoxes: [newSearchBox],
|
||
|
});
|
||
|
this.searchBox = newSearchBox;
|
||
|
this.isChoosingSearchBox = false;
|
||
|
|
||
|
this.$notify(
|
||
|
{
|
||
|
group: "alert",
|
||
|
type: "success",
|
||
|
title: "Saved",
|
||
|
text: "That has been saved in your preferences.",
|
||
|
},
|
||
|
-1,
|
||
|
);
|
||
|
} catch (err) {
|
||
|
this.$notify(
|
||
|
{
|
||
|
group: "alert",
|
||
|
type: "danger",
|
||
|
title: "Error Updating Search Settings",
|
||
|
text: "Try going to a different page and then coming back.",
|
||
|
},
|
||
|
-1,
|
||
|
);
|
||
|
console.error(
|
||
|
"Telling user to retry the location search setting because:",
|
||
|
err,
|
||
|
);
|
||
|
}
|
||
|
} else {
|
||
|
this.$notify(
|
||
|
{
|
||
|
group: "alert",
|
||
|
type: "warning",
|
||
|
title: "No Location Selected",
|
||
|
text: "Select a location on the map.",
|
||
|
},
|
||
|
-1,
|
||
|
);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public async forgetSearchBox() {
|
||
|
try {
|
||
|
await db.open();
|
||
|
db.settings.update(MASTER_SETTINGS_KEY, {
|
||
|
searchBoxes: [],
|
||
|
});
|
||
|
this.searchBox = null;
|
||
|
this.localCenterLat = 0;
|
||
|
this.localCenterLong = 0;
|
||
|
this.localLatDiff = DEFAULT_LAT_LONG_DIFF;
|
||
|
this.localLongDiff = DEFAULT_LAT_LONG_DIFF;
|
||
|
this.localZoom = DEFAULT_ZOOM;
|
||
|
this.isChoosingSearchBox = false;
|
||
|
this.isNewMarkerSet = false;
|
||
|
} catch (err) {
|
||
|
this.$notify(
|
||
|
{
|
||
|
group: "alert",
|
||
|
type: "danger",
|
||
|
title: "Error Updating Search Settings",
|
||
|
text: "Try going to a different page and then coming back.",
|
||
|
},
|
||
|
-1,
|
||
|
);
|
||
|
console.error(
|
||
|
"Telling user to retry the location search setting because:",
|
||
|
err,
|
||
|
);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public cancelSearchBoxSelect() {
|
||
|
this.isChoosingSearchBox = false;
|
||
|
this.localZoom = WORLD_ZOOM;
|
||
|
}
|
||
|
}
|
||
|
</script>
|