Trent Larson
12 months ago
6 changed files with 304 additions and 212 deletions
@ -0,0 +1,281 @@ |
|||||
|
<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> |
Loading…
Reference in new issue