|
|
@ -1,6 +1,5 @@ |
|
|
|
<template> |
|
|
|
<section |
|
|
|
v-if="isRegistered" |
|
|
|
id="sectionSearchLocation" |
|
|
|
class="bg-slate-100 rounded-md overflow-hidden px-4 py-4 mt-8 mb-8" |
|
|
|
aria-labelledby="searchLocationHeading" |
|
|
@ -8,28 +7,118 @@ |
|
|
|
<h2 id="searchLocationHeading" class="mb-2 font-bold"> |
|
|
|
Location for Searches |
|
|
|
</h2> |
|
|
|
<div v-if="searchAreaLabel" class="mb-2"> |
|
|
|
<span class="text-slate-700">Current Area: </span> |
|
|
|
<span class="font-mono">{{ searchAreaLabel }}</span> |
|
|
|
|
|
|
|
<!-- Read-only map display when search area is set --> |
|
|
|
<div v-if="searchBox" class="mb-4 aspect-video"> |
|
|
|
<l-map |
|
|
|
ref="map" |
|
|
|
:center="mapCenter" |
|
|
|
:zoom="mapZoom" |
|
|
|
class="!z-40 rounded-md" |
|
|
|
> |
|
|
|
<l-tile-layer |
|
|
|
url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png" |
|
|
|
layer-type="base" |
|
|
|
name="OpenStreetMap" |
|
|
|
/> |
|
|
|
<l-rectangle |
|
|
|
:bounds="mapBounds" |
|
|
|
:weight="2" |
|
|
|
color="#3b82f6" |
|
|
|
fill-color="#3b82f6" |
|
|
|
fill-opacity="0.2" |
|
|
|
/> |
|
|
|
</l-map> |
|
|
|
</div> |
|
|
|
|
|
|
|
<button |
|
|
|
class="w-full text-md bg-gradient-to-b from-blue-400 to-blue-700 shadow-[inset_0_-1px_0_0_rgba(0,0,0,0.5)] text-white px-4 py-2 rounded-md" |
|
|
|
@click="$router.push({ name: 'search-area' })" |
|
|
|
@click="navigateToSearchArea" |
|
|
|
> |
|
|
|
Set Search Area... |
|
|
|
{{ searchBox ? "Change Search Area..." : "Set Search Area..." }} |
|
|
|
</button> |
|
|
|
</section> |
|
|
|
</template> |
|
|
|
|
|
|
|
<script lang="ts"> |
|
|
|
import { Component, Vue, Prop, Emit } from "vue-facing-decorator"; |
|
|
|
import "leaflet/dist/leaflet.css"; |
|
|
|
import { Component, Vue, Prop } from "vue-facing-decorator"; |
|
|
|
import { LMap, LRectangle, LTileLayer } from "@vue-leaflet/vue-leaflet"; |
|
|
|
import { Router } from "vue-router"; |
|
|
|
import { BoundingBox } from "../db/tables/settings"; |
|
|
|
|
|
|
|
@Component({ name: "LocationSearchSection" }) |
|
|
|
@Component({ |
|
|
|
name: "LocationSearchSection", |
|
|
|
components: { |
|
|
|
LMap, |
|
|
|
LRectangle, |
|
|
|
LTileLayer, |
|
|
|
}, |
|
|
|
}) |
|
|
|
export default class LocationSearchSection extends Vue { |
|
|
|
@Prop({ required: true }) isRegistered!: boolean; |
|
|
|
@Prop({ required: false }) searchAreaLabel?: string; |
|
|
|
$router!: Router; |
|
|
|
|
|
|
|
@Prop({ required: false }) searchBox?: { |
|
|
|
name: string; |
|
|
|
bbox: BoundingBox; |
|
|
|
} | null; |
|
|
|
|
|
|
|
/** |
|
|
|
* Navigate to search area management page |
|
|
|
*/ |
|
|
|
navigateToSearchArea() { |
|
|
|
this.$router.push({ name: "search-area" }); |
|
|
|
} |
|
|
|
|
|
|
|
/** |
|
|
|
* Computed property for map center coordinates |
|
|
|
*/ |
|
|
|
get mapCenter(): [number, number] { |
|
|
|
if (!this.searchBox?.bbox) { |
|
|
|
return [0, 0]; |
|
|
|
} |
|
|
|
const bbox = this.searchBox.bbox; |
|
|
|
const centerLat = (bbox.maxLat + bbox.minLat) / 2; |
|
|
|
const centerLong = (bbox.eastLong + bbox.westLong) / 2; |
|
|
|
return [centerLat, centerLong]; |
|
|
|
} |
|
|
|
|
|
|
|
/** |
|
|
|
* Computed property for map zoom level |
|
|
|
*/ |
|
|
|
get mapZoom(): number { |
|
|
|
if (!this.searchBox?.bbox) { |
|
|
|
return 2; |
|
|
|
} |
|
|
|
// Calculate appropriate zoom based on bounding box size |
|
|
|
const bbox = this.searchBox.bbox; |
|
|
|
const latDiff = bbox.maxLat - bbox.minLat; |
|
|
|
const longDiff = bbox.eastLong - bbox.westLong; |
|
|
|
const maxDiff = Math.max(latDiff, longDiff); |
|
|
|
|
|
|
|
// Simple zoom calculation - adjust as needed |
|
|
|
if (maxDiff > 10) return 4; |
|
|
|
if (maxDiff > 5) return 6; |
|
|
|
if (maxDiff > 1) return 8; |
|
|
|
if (maxDiff > 0.1) return 10; |
|
|
|
return 12; |
|
|
|
} |
|
|
|
|
|
|
|
@Emit("set-search-area") |
|
|
|
setSearchArea() {} |
|
|
|
/** |
|
|
|
* Computed property for map bounds |
|
|
|
*/ |
|
|
|
get mapBounds(): [[number, number], [number, number]] { |
|
|
|
if (!this.searchBox?.bbox) { |
|
|
|
return [ |
|
|
|
[0, 0], |
|
|
|
[0, 0], |
|
|
|
]; |
|
|
|
} |
|
|
|
const bbox = this.searchBox.bbox; |
|
|
|
return [ |
|
|
|
[bbox.minLat, bbox.westLong], |
|
|
|
[bbox.maxLat, bbox.eastLong], |
|
|
|
]; |
|
|
|
} |
|
|
|
} |
|
|
|
</script> |
|
|
|