script[setup]: interfaces/map (#18424)

This commit is contained in:
Rijk van Zanten
2023-05-03 10:48:48 -04:00
committed by GitHub
parent bb4fd307cd
commit 90dbfbaa3a
2 changed files with 418 additions and 471 deletions

View File

@@ -61,7 +61,7 @@
</div>
</template>
<script lang="ts">
<script setup lang="ts">
import MapboxDraw from '@mapbox/mapbox-gl-draw';
import '@mapbox/mapbox-gl-draw/dist/mapbox-gl-draw.css';
import maplibre, {
@@ -75,7 +75,7 @@ import maplibre, {
NavigationControl,
} from 'maplibre-gl';
import 'maplibre-gl/dist/maplibre-gl.css';
import { computed, defineComponent, onMounted, onUnmounted, PropType, ref, toRefs, watch } from 'vue';
import { computed, onMounted, onUnmounted, ref, toRefs, watch } from 'vue';
import { useSettingsStore } from '@/stores/settings';
import { flatten, getBBox, getGeometryFormatForType, getParser, getSerializer } from '@/utils/geometry';
import { ButtonControl } from '@/utils/geometry/controls';
@@ -87,6 +87,9 @@ import '@mapbox/mapbox-gl-geocoder/dist/mapbox-gl-geocoder.css';
import { Geometry } from 'geojson';
import { debounce, isEqual, snakeCase } from 'lodash';
import { getMapStyle } from './style';
import { useAppStore } from '@/stores/app';
import { TranslateResult, useI18n } from 'vue-i18n';
import { getBasemapSources, getStyleFromBasemapSource } from '@/utils/geometry/basemap';
const activeLayers = [
'directus-point',
@@ -97,401 +100,364 @@ const activeLayers = [
'directus-polygon-and-line-vertex',
].flatMap((name) => [name + '.hot', name + '.cold']);
import { useAppStore } from '@/stores/app';
import { TranslateResult, useI18n } from 'vue-i18n';
const props = withDefaults(
defineProps<{
value: Record<string, unknown> | unknown[] | string | null;
type: 'geometry' | 'json' | 'csv' | 'string' | 'text';
fieldData?: Field;
loading?: boolean;
disabled?: boolean;
geometryType?: GeometryType;
defaultView?: Record<string, unknown>;
}>(),
{
loading: true,
defaultView: () => ({}),
}
);
import { getBasemapSources, getStyleFromBasemapSource } from '@/utils/geometry/basemap';
const emit = defineEmits<{
(e: 'input', value: Record<string, unknown> | unknown[] | string | null): void;
}>();
export default defineComponent({
props: {
type: {
type: String as PropType<'geometry' | 'json' | 'csv' | 'string' | 'text'>,
default: null,
},
fieldData: {
type: Object as PropType<Field | undefined>,
default: undefined,
},
value: {
type: [Object, Array, String] as PropType<any>,
default: null,
},
loading: {
type: Boolean,
default: true,
},
disabled: {
type: Boolean,
default: false,
},
geometryType: {
type: String as PropType<GeometryType>,
default: undefined,
},
defaultView: {
type: Object,
default: () => ({}),
},
},
emits: ['input'],
setup(props, { emit }) {
const { t } = useI18n();
const container = ref<HTMLElement | null>(null);
let map: Map;
let mapLoading = ref(true);
let currentGeometry: Geometry | null | undefined;
const { t } = useI18n();
const container = ref<HTMLElement | null>(null);
let map: Map;
let mapLoading = ref(true);
let currentGeometry: Geometry | null | undefined;
const geometryOptionsError = ref<string | null>();
const geometryParsingError = ref<string | TranslateResult>();
const geometryOptionsError = ref<string | null>();
const geometryParsingError = ref<string | TranslateResult>();
const geometryType = props.fieldData?.type.split('.')[1] as GeometryType;
const geometryFormat = getGeometryFormatForType(props.type)!;
const geometryType = props.fieldData?.type.split('.')[1] as GeometryType;
const geometryFormat = getGeometryFormatForType(props.type)!;
const settingsStore = useSettingsStore();
const mapboxKey = settingsStore.settings?.mapbox_key;
const settingsStore = useSettingsStore();
const mapboxKey = settingsStore.settings?.mapbox_key;
const basemaps = getBasemapSources();
const appStore = useAppStore();
const { basemap } = toRefs(appStore);
const basemaps = getBasemapSources();
const appStore = useAppStore();
const { basemap } = toRefs(appStore);
const style = computed(() => {
const source = basemaps.find((source) => source.name == basemap.value) ?? basemaps[0];
return basemap.value, getStyleFromBasemapSource(source);
});
let parse: GeoJSONParser;
let serialize: GeoJSONSerializer;
try {
parse = getParser({ geometryFormat, geometryField: 'value' });
serialize = getSerializer({ geometryFormat, geometryField: 'value' });
} catch (error: any) {
geometryOptionsError.value = error;
}
const selection = ref<GeoJSON.Feature[]>([]);
const location = ref<LngLatLike | null>();
const projection = ref<{ x: number; y: number } | null>();
function updateProjection() {
projection.value = !location.value ? null : map.project(location.value as any);
}
watch(location, updateProjection);
const controls = {
attribution: new AttributionControl(),
draw: new MapboxDraw(getDrawOptions(geometryType)),
fitData: new ButtonControl('mapboxgl-ctrl-fitdata', fitDataBounds),
navigation: new NavigationControl({
showCompass: false,
}),
geolocate: new GeolocateControl({
showUserLocation: false,
}),
geocoder: undefined as MapboxGeocoder | undefined,
};
if (mapboxKey) {
controls.geocoder = new MapboxGeocoder({
accessToken: mapboxKey,
collapsed: true,
flyTo: { speed: 1.4 },
marker: false,
mapboxgl: maplibre as any,
placeholder: t('layouts.map.find_location'),
});
}
const tooltipVisible = ref(false);
const tooltipMessage = ref('');
const tooltipPosition = ref({ x: 0, y: 0 });
function hideTooltip() {
tooltipVisible.value = false;
}
const updateTooltipDebounce = debounce((event: any) => {
const feature = event.features?.[0];
if (feature && feature.properties!.active === 'false') {
tooltipMessage.value = t('interfaces.map.click_to_select', { geometry: feature.geometry.type });
tooltipVisible.value = true;
tooltipPosition.value = event.point;
}
}, 200);
function updateTooltip(event: any) {
tooltipVisible.value = false;
updateTooltipDebounce({ point: event.point, features: event.features });
}
onMounted(() => {
const cleanup = setupMap();
onUnmounted(cleanup);
});
return {
t,
tooltipPosition,
tooltipVisible,
tooltipMessage,
container,
mapLoading,
resetValue,
geometryParsingError,
geometryOptionsError,
basemaps,
basemap,
location,
projection,
selection,
};
function setupMap(): () => void {
map = new Map({
container: container.value!,
style: style.value,
dragRotate: false,
logoPosition: 'bottom-left',
attributionControl: false,
...props.defaultView,
...(mapboxKey ? { accessToken: mapboxKey } : {}),
});
if (controls.geocoder) {
map.addControl(controls.geocoder as any, 'top-right');
controls.geocoder.on('result', (event: any) => {
location.value = event.result.center;
});
controls.geocoder.on('clear', () => {
location.value = null;
});
}
controls.geolocate.on('geolocate', (event: any) => {
const { longitude, latitude } = event.coords;
location.value = [longitude, latitude];
});
map.addControl(controls.attribution, 'bottom-left');
map.addControl(controls.navigation, 'top-left');
map.addControl(controls.geolocate, 'top-left');
map.addControl(controls.fitData, 'top-left');
map.addControl(controls.draw as any, 'top-left');
map.on('load', async () => {
map.resize();
mapLoading.value = false;
map.on('draw.create', handleDrawUpdate);
map.on('draw.delete', handleDrawUpdate);
map.on('draw.update', handleDrawUpdate);
map.on('draw.modechange', handleDrawModeChange);
map.on('draw.selectionchange', handleSelectionChange);
map.on('move', updateProjection);
for (const layer of activeLayers) {
map.on('mousedown', layer, hideTooltip);
map.on('mousemove', layer, updateTooltip);
map.on('mouseleave', layer, updateTooltip);
}
window.addEventListener('keydown', handleKeyDown);
});
watch(() => props.value, updateValue, { immediate: true });
watch(() => style.value, updateStyle);
watch(() => props.disabled, updateStyle);
return () => {
window.removeEventListener('keydown', handleKeyDown);
map.remove();
};
}
function updateValue(value: any) {
if (!value) {
controls.draw.deleteAll();
currentGeometry = null;
if (geometryType) {
const snaked = snakeCase(geometryType.replace('Multi', ''));
const mode = `draw_${snaked}` as any;
controls.draw.changeMode(mode);
}
} else {
if (!isEqual(value, currentGeometry && serialize(currentGeometry))) {
loadValueFromProps();
controls.draw.changeMode('simple_select');
}
}
if (props.disabled) {
controls.draw.changeMode('static');
}
}
function updateStyle() {
map.removeControl(controls.draw as any);
map.setStyle(style.value, { diff: false });
controls.draw = new MapboxDraw(getDrawOptions(geometryType));
map.addControl(controls.draw as any, 'top-left');
loadValueFromProps();
}
function resetValue(hard: boolean) {
geometryParsingError.value = undefined;
if (hard) emit('input', null);
}
function fitDataBounds(options: CameraOptions & AnimationOptions) {
if (map && currentGeometry) {
const bbox = getBBox(currentGeometry);
map.fitBounds(bbox as LngLatBoundsLike, {
padding: 80,
maxZoom: 8,
...options,
});
}
}
function getDrawOptions(type: GeometryType): any {
const options = {
styles: getMapStyle(),
controls: {},
userProperties: true,
displayControlsDefault: false,
modes: Object.assign(MapboxDraw.modes, {
static: StaticMode,
}),
} as any;
if (props.disabled) {
return options;
}
if (!type) {
options.controls.line_string = true;
options.controls.polygon = true;
options.controls.point = true;
options.controls.trash = true;
return options;
} else {
const base = snakeCase(type!.replace('Multi', ''));
options.controls[base] = true;
options.controls.trash = true;
return options;
}
}
function isTypeCompatible(a?: GeometryType, b?: GeometryType): boolean {
if (!a || !b) {
return true;
}
if (a.startsWith('Multi')) {
return a.replace('Multi', '') == b.replace('Multi', '');
}
return a == b;
}
function loadValueFromProps() {
try {
controls.draw.deleteAll();
const initialValue = parse(props);
if (!initialValue) {
return;
}
if (!props.disabled && !isTypeCompatible(geometryType, initialValue!.type)) {
geometryParsingError.value = t('interfaces.map.unexpected_geometry', {
expected: geometryType,
got: initialValue!.type,
});
}
const flattened = flatten(initialValue);
for (const geometry of flattened) {
controls.draw.add(geometry);
}
currentGeometry = getCurrentGeometry();
currentGeometry!.bbox = getBBox(currentGeometry!);
if (geometryParsingError.value) {
const bbox = getBBox(initialValue!) as LngLatBoundsLike;
map.fitBounds(bbox, { padding: 0, maxZoom: 8, duration: 0 });
} else {
fitDataBounds({ duration: 0 });
}
} catch (error: any) {
geometryParsingError.value = error;
}
}
function getCurrentGeometry(): Geometry | null {
const features = controls.draw.getAll().features;
const geometries = features.map((f) => f.geometry) as (SimpleGeometry | MultiGeometry)[];
let result: Geometry;
if (geometries.length == 0) {
return null;
} else if (!geometryType) {
if (geometries.length > 1) {
result = { type: 'GeometryCollection', geometries };
} else {
result = geometries[0];
}
} else if (geometryType.startsWith('Multi')) {
const coordinates = geometries
.filter(({ type }) => `Multi${type}` == geometryType)
.map(({ coordinates }) => coordinates);
result = { type: geometryType, coordinates } as Geometry;
} else {
result = geometries[geometries.length - 1];
}
return result;
}
function handleDrawModeChange(event: any) {
if (!props.disabled && event.mode.startsWith('draw') && geometryType && !geometryType.startsWith('Multi')) {
for (const feature of controls.draw.getAll().features.slice(0, -1)) {
controls.draw.delete(feature.id as string);
}
}
}
function handleSelectionChange(event: any) {
selection.value = event.features;
}
function handleDrawUpdate() {
currentGeometry = getCurrentGeometry();
if (!currentGeometry) {
controls.draw.deleteAll();
emit('input', null);
} else {
emit('input', serialize(currentGeometry));
}
}
function handleKeyDown(event: any) {
if ([8, 46].includes(event.keyCode)) {
controls.draw.trash();
}
}
},
const style = computed(() => {
const source = basemaps.find((source) => source.name == basemap.value) ?? basemaps[0];
return basemap.value, getStyleFromBasemapSource(source);
});
let parse: GeoJSONParser;
let serialize: GeoJSONSerializer;
try {
parse = getParser({ geometryFormat, geometryField: 'value' });
serialize = getSerializer({ geometryFormat, geometryField: 'value' });
} catch (error: any) {
geometryOptionsError.value = error;
}
const selection = ref<GeoJSON.Feature[]>([]);
const location = ref<LngLatLike | null>();
const projection = ref<{ x: number; y: number } | null>();
function updateProjection() {
projection.value = !location.value ? null : map.project(location.value as any);
}
watch(location, updateProjection);
const controls = {
attribution: new AttributionControl(),
draw: new MapboxDraw(getDrawOptions(geometryType)),
fitData: new ButtonControl('mapboxgl-ctrl-fitdata', fitDataBounds),
navigation: new NavigationControl({
showCompass: false,
}),
geolocate: new GeolocateControl({
showUserLocation: false,
}),
geocoder: undefined as MapboxGeocoder | undefined,
};
if (mapboxKey) {
controls.geocoder = new MapboxGeocoder({
accessToken: mapboxKey,
collapsed: true,
flyTo: { speed: 1.4 },
marker: false,
mapboxgl: maplibre as any,
placeholder: t('layouts.map.find_location'),
});
}
const tooltipVisible = ref(false);
const tooltipMessage = ref('');
const tooltipPosition = ref({ x: 0, y: 0 });
function hideTooltip() {
tooltipVisible.value = false;
}
const updateTooltipDebounce = debounce((event: any) => {
const feature = event.features?.[0];
if (feature && feature.properties!.active === 'false') {
tooltipMessage.value = t('interfaces.map.click_to_select', { geometry: feature.geometry.type });
tooltipVisible.value = true;
tooltipPosition.value = event.point;
}
}, 200);
function updateTooltip(event: any) {
tooltipVisible.value = false;
updateTooltipDebounce({ point: event.point, features: event.features });
}
onMounted(() => {
const cleanup = setupMap();
onUnmounted(cleanup);
});
function setupMap(): () => void {
map = new Map({
container: container.value!,
style: style.value,
dragRotate: false,
logoPosition: 'bottom-left',
attributionControl: false,
...props.defaultView,
...(mapboxKey ? { accessToken: mapboxKey } : {}),
});
if (controls.geocoder) {
map.addControl(controls.geocoder as any, 'top-right');
controls.geocoder.on('result', (event: any) => {
location.value = event.result.center;
});
controls.geocoder.on('clear', () => {
location.value = null;
});
}
controls.geolocate.on('geolocate', (event: any) => {
const { longitude, latitude } = event.coords;
location.value = [longitude, latitude];
});
map.addControl(controls.attribution, 'bottom-left');
map.addControl(controls.navigation, 'top-left');
map.addControl(controls.geolocate, 'top-left');
map.addControl(controls.fitData, 'top-left');
map.addControl(controls.draw as any, 'top-left');
map.on('load', async () => {
map.resize();
mapLoading.value = false;
map.on('draw.create', handleDrawUpdate);
map.on('draw.delete', handleDrawUpdate);
map.on('draw.update', handleDrawUpdate);
map.on('draw.modechange', handleDrawModeChange);
map.on('draw.selectionchange', handleSelectionChange);
map.on('move', updateProjection);
for (const layer of activeLayers) {
map.on('mousedown', layer, hideTooltip);
map.on('mousemove', layer, updateTooltip);
map.on('mouseleave', layer, updateTooltip);
}
window.addEventListener('keydown', handleKeyDown);
});
watch(() => props.value, updateValue, { immediate: true });
watch(() => style.value, updateStyle);
watch(() => props.disabled, updateStyle);
return () => {
window.removeEventListener('keydown', handleKeyDown);
map.remove();
};
}
function updateValue(value: any) {
if (!value) {
controls.draw.deleteAll();
currentGeometry = null;
if (geometryType) {
const snaked = snakeCase(geometryType.replace('Multi', ''));
const mode = `draw_${snaked}` as any;
controls.draw.changeMode(mode);
}
} else {
if (!isEqual(value, currentGeometry && serialize(currentGeometry))) {
loadValueFromProps();
controls.draw.changeMode('simple_select');
}
}
if (props.disabled) {
controls.draw.changeMode('static');
}
}
function updateStyle() {
map.removeControl(controls.draw as any);
map.setStyle(style.value, { diff: false });
controls.draw = new MapboxDraw(getDrawOptions(geometryType));
map.addControl(controls.draw as any, 'top-left');
loadValueFromProps();
}
function resetValue(hard: boolean) {
geometryParsingError.value = undefined;
if (hard) emit('input', null);
}
function fitDataBounds(options: CameraOptions & AnimationOptions) {
if (map && currentGeometry) {
const bbox = getBBox(currentGeometry);
map.fitBounds(bbox as LngLatBoundsLike, {
padding: 80,
maxZoom: 8,
...options,
});
}
}
function getDrawOptions(type: GeometryType): any {
const options = {
styles: getMapStyle(),
controls: {},
userProperties: true,
displayControlsDefault: false,
modes: Object.assign(MapboxDraw.modes, {
static: StaticMode,
}),
} as any;
if (props.disabled) {
return options;
}
if (!type) {
options.controls.line_string = true;
options.controls.polygon = true;
options.controls.point = true;
options.controls.trash = true;
return options;
} else {
const base = snakeCase(type!.replace('Multi', ''));
options.controls[base] = true;
options.controls.trash = true;
return options;
}
}
function isTypeCompatible(a?: GeometryType, b?: GeometryType): boolean {
if (!a || !b) {
return true;
}
if (a.startsWith('Multi')) {
return a.replace('Multi', '') == b.replace('Multi', '');
}
return a == b;
}
function loadValueFromProps() {
try {
controls.draw.deleteAll();
const initialValue = parse(props);
if (!initialValue) {
return;
}
if (!props.disabled && !isTypeCompatible(geometryType, initialValue!.type)) {
geometryParsingError.value = t('interfaces.map.unexpected_geometry', {
expected: geometryType,
got: initialValue!.type,
});
}
const flattened = flatten(initialValue);
for (const geometry of flattened) {
controls.draw.add(geometry);
}
currentGeometry = getCurrentGeometry();
currentGeometry!.bbox = getBBox(currentGeometry!);
if (geometryParsingError.value) {
const bbox = getBBox(initialValue!) as LngLatBoundsLike;
map.fitBounds(bbox, { padding: 0, maxZoom: 8, duration: 0 });
} else {
fitDataBounds({ duration: 0 });
}
} catch (error: any) {
geometryParsingError.value = error;
}
}
function getCurrentGeometry(): Geometry | null {
const features = controls.draw.getAll().features;
const geometries = features.map((f) => f.geometry) as (SimpleGeometry | MultiGeometry)[];
let result: Geometry;
if (geometries.length == 0) {
return null;
} else if (!geometryType) {
if (geometries.length > 1) {
result = { type: 'GeometryCollection', geometries };
} else {
result = geometries[0];
}
} else if (geometryType.startsWith('Multi')) {
const coordinates = geometries
.filter(({ type }) => `Multi${type}` == geometryType)
.map(({ coordinates }) => coordinates);
result = { type: geometryType, coordinates } as Geometry;
} else {
result = geometries[geometries.length - 1];
}
return result;
}
function handleDrawModeChange(event: any) {
if (!props.disabled && event.mode.startsWith('draw') && geometryType && !geometryType.startsWith('Multi')) {
for (const feature of controls.draw.getAll().features.slice(0, -1)) {
controls.draw.delete(feature.id as string);
}
}
}
function handleSelectionChange(event: any) {
selection.value = event.features;
}
function handleDrawUpdate() {
currentGeometry = getCurrentGeometry();
if (!currentGeometry) {
controls.draw.deleteAll();
emit('input', null);
} else {
emit('input', serialize(currentGeometry));
}
}
function handleKeyDown(event: any) {
if ([8, 46].includes(event.keyCode)) {
controls.draw.trash();
}
}
</script>
<style lang="scss" scoped>

View File

@@ -1,6 +1,6 @@
<template>
<div class="form-grid">
<div v-if="!nativeGeometryType && field.type !== 'csv'" class="field half-left">
<div v-if="!nativeGeometryType && field?.type !== 'csv'" class="field half-left">
<div class="type-label">{{ t('interfaces.map.geometry_type') }}</div>
<v-select
v-model="geometryType"
@@ -16,104 +16,85 @@
</div>
</template>
<script lang="ts">
import { useI18n } from 'vue-i18n';
import { ref, defineComponent, PropType, watch, onMounted, onUnmounted, computed, toRefs } from 'vue';
import { GEOMETRY_TYPES } from '@directus/constants';
import { Field, GeometryType, GeometryOptions } from '@directus/types';
import { getBasemapSources, getStyleFromBasemapSource } from '@/utils/geometry/basemap';
import 'maplibre-gl/dist/maplibre-gl.css';
import { Map, CameraOptions } from 'maplibre-gl';
<script setup lang="ts">
import { useAppStore } from '@/stores/app';
import { useSettingsStore } from '@/stores/settings';
import { getBasemapSources, getStyleFromBasemapSource } from '@/utils/geometry/basemap';
import { GEOMETRY_TYPES } from '@directus/constants';
import { Field, GeometryOptions, GeometryType } from '@directus/types';
import { CameraOptions, Map } from 'maplibre-gl';
import 'maplibre-gl/dist/maplibre-gl.css';
import { computed, onMounted, onUnmounted, ref, toRefs, watch } from 'vue';
import { useI18n } from 'vue-i18n';
export default defineComponent({
props: {
collection: {
type: String,
required: true,
},
field: {
type: Object as PropType<Field>,
default: null,
},
value: {
type: Object as PropType<GeometryOptions & { defaultView?: CameraOptions }>,
default: null,
},
},
emits: ['input'],
setup(props, { emit }) {
const { t } = useI18n();
const props = defineProps<{
collection: string;
field?: Field;
value?: GeometryOptions & { defaultView?: CameraOptions };
}>();
const nativeGeometryType = computed(() => (props.field?.type.split('.')[1] as GeometryType) ?? 'Point');
const geometryType = ref<GeometryType>(nativeGeometryType.value ?? props.value?.geometryType ?? 'Point');
const defaultView = ref<CameraOptions | undefined>(props.value?.defaultView);
const emit = defineEmits(['input']);
const settingsStore = useSettingsStore();
const { t } = useI18n();
watch(() => props.field?.type, watchType);
watch(nativeGeometryType, watchNativeType);
watch([geometryType, defaultView], input, { immediate: true });
const nativeGeometryType = computed(() => (props.field?.type.split('.')[1] as GeometryType) ?? 'Point');
const geometryType = ref<GeometryType>(nativeGeometryType.value ?? props.value?.geometryType ?? 'Point');
const defaultView = ref<CameraOptions | undefined>(props.value?.defaultView);
function watchType(type: string | undefined) {
if (type === 'csv') geometryType.value = 'Point';
}
const settingsStore = useSettingsStore();
function watchNativeType(type: GeometryType) {
geometryType.value = type;
}
watch(() => props.field?.type, watchType);
watch(nativeGeometryType, watchNativeType);
watch([geometryType, defaultView], input, { immediate: true });
function input() {
emit('input', {
defaultView,
geometryType: geometryType.value,
});
}
function watchType(type: string | undefined) {
if (type === 'csv') geometryType.value = 'Point';
}
const mapContainer = ref<HTMLElement | null>(null);
let map: Map;
function watchNativeType(type: GeometryType) {
geometryType.value = type;
}
const mapboxKey = settingsStore.settings?.mapbox_key;
const basemaps = getBasemapSources();
const appStore = useAppStore();
const { basemap } = toRefs(appStore);
function input() {
emit('input', {
defaultView,
geometryType: geometryType.value,
});
}
const style = computed(() => {
const source = basemaps.find((source) => source.name == basemap.value) ?? basemaps[0];
return getStyleFromBasemapSource(source);
});
const mapContainer = ref<HTMLElement | null>(null);
let map: Map;
onMounted(() => {
map = new Map({
container: mapContainer.value!,
style: style.value,
...(defaultView.value || {}),
...(mapboxKey ? { accessToken: mapboxKey } : {}),
});
const mapboxKey = settingsStore.settings?.mapbox_key;
const basemaps = getBasemapSources();
const appStore = useAppStore();
const { basemap } = toRefs(appStore);
map.on('moveend', () => {
defaultView.value = {
center: map.getCenter(),
zoom: map.getZoom(),
bearing: map.getBearing(),
pitch: map.getPitch(),
};
});
});
const style = computed(() => {
const source = basemaps.find((source) => source.name == basemap.value) ?? basemaps[0];
return getStyleFromBasemapSource(source);
});
onUnmounted(() => {
map.remove();
});
onMounted(() => {
map = new Map({
container: mapContainer.value!,
style: style.value,
...(defaultView.value || {}),
...(mapboxKey ? { accessToken: mapboxKey } : {}),
});
return {
t,
nativeGeometryType,
GEOMETRY_TYPES,
geometryType,
mapContainer,
map.on('moveend', () => {
defaultView.value = {
center: map.getCenter(),
zoom: map.getZoom(),
bearing: map.getBearing(),
pitch: map.getPitch(),
};
},
});
});
onUnmounted(() => {
map.remove();
});
</script>