Set initial camera based on location in compliance

This commit is contained in:
Eli Ribble 2026-04-10 14:20:04 +00:00
parent 97acdb0e2c
commit c48aebcb0b
No known key found for this signature in database
6 changed files with 83 additions and 29 deletions

View file

@ -177,7 +177,8 @@ interface Emits {
// Props
interface Props {
modelValue: Camera | null;
initialCamera?: Camera;
modelValue: Camera;
markers?: Marker[];
}
@ -225,12 +226,7 @@ function deactivateMap() {
function initializeMap() {
if (!mapContainer.value) return;
let bounds = boundsDefault();
if (props.markers.length > 0) {
bounds = boundsMarkers(props.markers);
}
const _map = new maplibregl.Map({
bounds: bounds,
container: mapContainer.value,
style: "https://tiles.stadiamaps.com/styles/alidade_smooth.json",
// Disable interactions by default
@ -239,6 +235,30 @@ function initializeMap() {
scrollZoom: false,
touchZoomRotate: false,
});
if (props.markers.length > 0) {
_map.fitBounds(boundsMarkers(props.markers));
} else if (props.initialCamera) {
_map.jumpTo({
center: [
props.initialCamera.location.longitude,
props.initialCamera.location.latitude,
],
zoom: props.initialCamera.zoom,
});
} else if (
props.modelValue.location.latitude != 0 ||
props.modelValue.location.longitude != 0
) {
_map.jumpTo({
center: [
props.modelValue.location.longitude,
props.modelValue.location.latitude,
],
zoom: props.modelValue.zoom,
});
} else {
_map.fitBounds(boundsDefault());
}
_map.addControl(new maplibregl.NavigationControl(), "top-left");
map.value = _map;
_map.on("click", (e: maplibregl.MapLayerMouseEvent) => {

View file

@ -50,10 +50,11 @@
<label class="form-label fw-semibold">Location Preview</label>
<div class="map-container">
<MapLocator
v-model="currentCamera"
:initialCamera="initialCamera"
:markers="markers"
@click="doMapClick"
@marker-drag-end="doMapMarkerDragEnd"
v-model="currentCamera"
/>
</div>
</div>
@ -64,17 +65,18 @@ import AddressSuggestion from "@/components/AddressSuggestion.vue";
import MapLocator from "@/components/MapLocator.vue";
import type { Address, Geocode, GeocodeSuggestion, Location } from "@/type/api";
import { useGeocodeStore } from "@/store/geocode";
import type { Camera, Locator } from "@/type/map";
import { Camera, Locator } from "@/type/map";
import type { Marker } from "@/types";
interface Emits {
(e: "update:modelValue", value: Locator): void;
}
interface Props {
initialCamera?: Camera;
modelValue: Locator;
}
const address = ref<string>("");
const currentCamera = ref<Camera | null>(null);
const currentCamera = ref<Camera>(new Camera());
const emit = defineEmits<Emits>();
const geocode = useGeocodeStore();
const markers = computed((): Marker[] => {

View file

@ -10,7 +10,10 @@
Please enter the address so we can match your response with our records.
</p>
<AddressAndMapLocator v-model="modelValue.locator" />
<AddressAndMapLocator
:initialCamera="initialCamera"
v-model="modelValue.locator"
/>
<div class="d-flex gap-2 mt-4">
<RouterLink class="btn btn-outline-secondary" to="../compliance">
@ -24,7 +27,7 @@
</div>
</template>
<script setup lang="ts">
import { ref } from "vue";
import { computed, ref } from "vue";
import { router } from "@/rmo/router";
import type { District } from "@/type/api";
@ -32,7 +35,7 @@ import HeaderCompliance from "@/rmo/components/HeaderCompliance.vue";
import ProgressBarCompliance from "@/rmo/components/ProgressBarCompliance.vue";
import AddressAndMapLocator from "@/rmo/components/AddressAndMapLocator.vue";
import { Compliance } from "@/rmo/view/Compliance.vue";
import { Locator } from "@/type/map";
import { Camera, Locator } from "@/type/map";
interface Emits {
(e: "doLocator"): void;
@ -45,6 +48,15 @@ interface Props {
const emit = defineEmits<Emits>();
const error = ref<string>("");
const props = defineProps<Props>();
const initialCamera = computed((): Camera | undefined => {
if (props.modelValue.location) {
return {
location: props.modelValue.location,
zoom: 15,
};
}
return undefined;
});
function doContinue() {
emit("update:modelValue", props.modelValue);
emit("doLocator");

View file

@ -43,7 +43,8 @@ import { useStoreDistrict } from "@/rmo/store/district";
import { useStoreLocal } from "@/store/local";
import { useStoreLocation } from "@/store/location";
import Intro from "@/rmo/content/compliance/Intro.vue";
import { type District, PermissionAccess, type PublicReport } from "@/type/api";
import type { District, Location, PublicReport } from "@/type/api";
import { PermissionAccess } from "@/type/api";
import { Locator } from "@/type/map";
import { type Contact } from "@/rmo/content/compliance/Contact.vue";
import { type Permission } from "@/rmo/content/compliance/Permission.vue";
@ -51,6 +52,7 @@ import { type Permission } from "@/rmo/content/compliance/Permission.vue";
export interface Compliance {
comments: string;
contact: Contact;
location: Location;
locator: Locator;
images: Image[];
permission: Permission;
@ -70,6 +72,10 @@ const compliance = ref<Compliance>({
email: "",
},
images: [],
location: {
latitude: 0,
longitude: 0,
},
locator: {
address: {
country: "",
@ -134,6 +140,7 @@ onMounted(() => {
storeLocation
.get()
.then((loc: GeolocationPosition) => {
compliance.value.location = loc.coords;
createReport(session_id, loc);
})
.catch((e) => {

View file

@ -4,16 +4,18 @@ export enum PermissionAccess {
UNSELECTED = "unselected",
WITH_OWNER = "with-owner",
}
export interface Address {
country: string;
gid: string;
locality: string;
number: string;
postal_code: string;
raw: string;
region: string;
street: string;
unit: string;
export class Address {
constructor(
public country: string,
public gid: string,
public locality: string,
public number: string,
public postal_code: string,
public raw: string,
public region: string,
public street: string,
public unit: string,
) {}
}
export interface Bounds {
min: Location;
@ -32,10 +34,15 @@ export interface District {
url_logo: string;
url_website: string;
}
export interface Location {
export class Location {
accuracy?: number;
latitude: number;
longitude: number;
constructor(latitude: number = 0, longitude: number = 0, accuracy?: number) {
this.accuracy = accuracy;
this.latitude = latitude;
this.longitude = longitude;
}
}
export interface GeocodeSuggestion {
detail: string;

View file

@ -1,13 +1,19 @@
import maplibregl from "maplibre-gl";
import type { Address, Location } from "@/type/api";
import { Address, Location } from "@/type/api";
export interface Camera {
export class Camera {
location: Location;
zoom: number;
constructor(location: Location = new Location(), zoom: number = 0) {
this.location = location;
this.zoom = zoom;
}
}
export interface Locator {
address: Address;
location: Location;
export class Locator {
constructor(
public address: Address,
public location: Location,
) {}
}
export type MoveEndEventInternal = maplibregl.MapLibreEvent<
| maplibregl.MapMouseEvent