Map layout and interface improvements (#9288)

* Map layout and interface improvements
* Fix marker not showing up on geocoder search
* Replaced geocoder search placeholder
* Fix geocoder hit area
* Fix item popup positioning
* Removed unselect button
* Removed "No results" popup
* Removed option to filter map on demand vs automatically
* Renamed Geometry field option
* Added placeholder to template option
* Hide "Delete" button when no feature are selected

* Lint fix

Co-authored-by: rijkvanzanten <rijkvanzanten@me.com>
This commit is contained in:
Oreille
2021-11-01 21:33:09 +01:00
committed by GitHub
parent 40917d3cf5
commit 6331ad0347
20 changed files with 66 additions and 248 deletions

View File

@@ -1,6 +1,13 @@
<template>
<div class="interface-map">
<div class="map" :class="{ loading: mapLoading, error: geometryParsingError || geometryOptionsError }">
<div
class="map"
:class="{
loading: mapLoading,
error: geometryParsingError || geometryOptionsError,
'has-selection': selection.length > 0,
}"
>
<div ref="container" />
</div>
<div
@@ -58,7 +65,7 @@
import 'maplibre-gl/dist/maplibre-gl.css';
import '@mapbox/mapbox-gl-draw/dist/mapbox-gl-draw.css';
import { defineComponent, onMounted, onUnmounted, PropType, ref, watch, toRefs, computed } from 'vue';
import {
import maplibre, {
LngLatLike,
LngLatBoundsLike,
AnimationOptions,
@@ -66,7 +73,6 @@ import {
Map,
NavigationControl,
GeolocateControl,
PointLike,
} from 'maplibre-gl';
import MapboxDraw from '@mapbox/mapbox-gl-draw';
// @ts-ignore
@@ -152,6 +158,7 @@ export default defineComponent({
const geometryType = (props.fieldData?.schema?.geometry_type ?? props.geometryType) as GeometryType;
const geometryFormat = props.geometryFormat || getGeometryFormatForType(props.type)!;
const mapboxKey = getSetting('mapbox_key');
const basemaps = getBasemapSources();
const appStore = useAppStore();
const { basemap } = toRefs(appStore);
@@ -169,6 +176,8 @@ export default defineComponent({
geometryOptionsError.value = error;
}
const selection = ref<GeoJSON.Feature[]>([]);
const location = ref<LngLatLike | null>();
const projection = ref<{ x: number; y: number } | null>();
function updateProjection() {
@@ -176,8 +185,6 @@ export default defineComponent({
}
watch(location, updateProjection);
const mapboxKey = getSetting('mapbox_key');
const controls = {
draw: new MapboxDraw(getDrawOptions(geometryType)),
fitData: new ButtonControl('mapboxgl-ctrl-fitdata', fitDataBounds),
@@ -194,6 +201,8 @@ export default defineComponent({
collapsed: true,
flyTo: { speed: 1.4 },
marker: false,
mapboxgl: maplibre as any,
placeholder: t('layouts.map.find_location'),
}) as any),
};
@@ -238,6 +247,7 @@ export default defineComponent({
basemap,
location,
projection,
selection,
};
function setupMap(): () => void {
@@ -275,6 +285,7 @@ export default defineComponent({
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);
@@ -437,6 +448,10 @@ export default defineComponent({
}
}
function handleSelectionChange(event: any) {
selection.value = event.features;
}
function handleDrawUpdate() {
currentGeometry = getCurrentGeometry();
if (!currentGeometry) {
@@ -447,7 +462,7 @@ export default defineComponent({
}
}
function handleKeyDown(event) {
function handleKeyDown(event: any) {
if ([8, 46].includes(event.keyCode)) {
controls.draw.trash();
}
@@ -477,6 +492,10 @@ export default defineComponent({
width: 100%;
height: 100%;
}
&:not(.has-selection) :deep(.mapbox-gl-draw_trash) {
display: none;
}
}
.v-info {
@@ -528,13 +547,13 @@ export default defineComponent({
pointer-events: none;
}
:deep(.fade-enter-active),
:deep(.fade-leave-active) {
.fade-enter-active,
.fade-leave-active {
transition: opacity var(--medium) var(--transition);
}
:deep(.fade-enter-from),
:deep(.fade-leave-to) {
.fade-enter-from,
.fade-leave-to {
opacity: 0;
}
</style>

View File

@@ -993,7 +993,7 @@ field_options:
auth_password_policy:
none_text: Няма - не се препоръчва
weak_text: Слаба - минимум от 8 символа
strong_text: Силна - главни, малки, числа и специални символи
strong_text: Силна - главни, малки, числа и специални символи
storage_asset_presets:
fit:
contain_text: Напасване (запазване на съотношението)
@@ -1557,7 +1557,6 @@ layouts:
map: Географска карта
basemap: Основна карта
layers: Слоеве
edit_custom_layers: Редактиране на слоевете
cluster_options: Настройки за групиране
cluster: Групиране на близките обекти
cluster_radius: Радиус за групиране
@@ -1565,11 +1564,6 @@ layouts:
cluster_maxzoom: Максимално увеличение при групиране
field: Геометрия
invalid_geometry: Невалидна геометрия
auto_location_filter: Филтриране според изгледа
search_this_area: Търсене в тази зона
clear_data_filter: Изчистване на филтрирането
clear_location_filter: Изчистване на филтрирането
no_results_here: Няма резултати в тази зона
panels:
metric:
name: Метричен Индикатор

View File

@@ -1319,7 +1319,6 @@ layouts:
map: Mapa
basemap: Mapa base
layers: Capes
edit_custom_layers: Edita capes
cluster_options: Opcions de clustering
cluster_radius: Radi del cluster
cluster_minpoints: Mida mínima del clúster

View File

@@ -1475,18 +1475,12 @@ layouts:
map:
map: Kort
layers: Lag
edit_custom_layers: Rediger Lag
cluster_options: Indstillinger for klyngedannelse
cluster: Klynge Nærliggende Data
cluster_minpoints: Mindste klyngestørrelse
cluster_maxzoom: Maksimum zoom til klyngedannelse
field: Geometri
invalid_geometry: Ugyldig geometri
auto_location_filter: Auto-filter inden for visning
search_this_area: Søg i dette område
clear_data_filter: Ryd datafilter
clear_location_filter: Ryd placeringsfilter
no_results_here: Ingen resultater i dette område
panels:
metric:
name: Metrisk

View File

@@ -1557,7 +1557,6 @@ layouts:
map: Karte
basemap: Basiskarte
layers: Ebenen
edit_custom_layers: Ebenen bearbeiten
cluster_options: Cluster-Optionen
cluster: Cluster Nachbardaten
cluster_radius: Cluster-Radius
@@ -1565,11 +1564,6 @@ layouts:
cluster_maxzoom: Maximaler Zoom für Cluster
field: Dimensionen
invalid_geometry: Ungültige Geometrie
auto_location_filter: Auto-Filter in der Ansicht
search_this_area: Diesen Bereich durchsuchen
clear_data_filter: Datenfilter löschen
clear_location_filter: Standortfilter löschen
no_results_here: Keine Ergebnisse in diesem Bereich
panels:
metric:
name: Metrik

View File

@@ -1571,19 +1571,15 @@ layouts:
map: Map
basemap: Basemap
layers: Layers
edit_custom_layers: Edit Layers
cluster_options: Clustering options
cluster: Cluster Nearby Data
cluster_radius: Cluster radius
cluster_minpoints: Cluster minimum size
cluster_maxzoom: Maximum zoom for clustering
field: Geometry
field: Geospatial Field
invalid_geometry: Invalid geometry
auto_location_filter: Auto-Filter within View
search_this_area: Search this area
clear_data_filter: Clear data filter
clear_location_filter: Clear location filter
no_results_here: No results in this area
find_location: Find location...
default_template: Using Collection Default...
panels:
metric:

View File

@@ -1403,7 +1403,7 @@ interfaces:
name: Détail du groupe
description: Rendre les champs comme une section pliable
show_header: En-tête de groupe
header_icon: Icônes de l'en-tête
header_icon: Icônes de l'en-tête
header_color: Couleur d'en-tête
start_open: Démarrer Ouverture
start_closed: Commencer réduit
@@ -1522,20 +1522,14 @@ layouts:
end_date_field: Champ Date de fin
map:
map: Carte
basemap: Carte de base
basemap: Fond de carte
layers: Afficher...
edit_custom_layers: Modifier la couche
cluster_options: Options de regroupement
cluster_radius: Rayon de grappe
cluster_minpoints: Taille minimale du cluster
cluster_maxzoom: Zoom maximum pour la grappe
field: Géométrie
field: Champ de la géométrie
invalid_geometry: Géométrie invalide
auto_location_filter: Filtre automatique dans la vue
search_this_area: Chercher dans cette zone
clear_data_filter: Réinitialiser le filtre
clear_location_filter: Réinitialiser le filtre de localisation
no_results_here: Aucun résultat dans cette zone
panels:
metric:
name: Indicateurs

View File

@@ -1495,7 +1495,6 @@ layouts:
map: Térkép
basemap: Alaptérkép
layers: Rétegek
edit_custom_layers: Rétegek szerkesztése
cluster_options: Klaszterezés beállításai
cluster_radius: Klaszter sugara
cluster_minpoints: Minimális klaszter méret

View File

@@ -1530,7 +1530,6 @@ layouts:
map: Mappa
basemap: Mappa base
layers: Livelli
edit_custom_layers: Modifica i livelli
cluster_options: Opzioni di raggruppamento
cluster: Raggruppa dati vicini
cluster_radius: Raggio del Cluster
@@ -1538,11 +1537,6 @@ layouts:
cluster_maxzoom: Zoom massimo per il raggruppamento
field: Geometria
invalid_geometry: Geometria non valida
auto_location_filter: Filtro automatico nella vista
search_this_area: Cerca in quest'area
clear_data_filter: Rimuovi il filtro sui dati
clear_location_filter: Rimuovi il filtro sulla posizione
no_results_here: Non ci sono risultati in quest'area
panels:
metric:
name: Metrica

View File

@@ -1554,7 +1554,6 @@ layouts:
map: Mapa
basemap: Mapa bazowa
layers: Warstwy
edit_custom_layers: Edytuj warstwy
cluster_options: Opcje klastrowania
cluster: Klaster danych w pobliżu
cluster_radius: Promień klastra
@@ -1562,11 +1561,6 @@ layouts:
cluster_maxzoom: Maksymalne powiększenie klastrów
field: Geometria
invalid_geometry: Nieprawidłowa geometria
auto_location_filter: Automatyczne filtrowanie w widoku
search_this_area: Przeszukaj ten obszar
clear_data_filter: Wyczyść filtr danych
clear_location_filter: Wyczyść filtr lokalizacji
no_results_here: Brak wyników w tym obszarze
panels:
metric:
name: Metryczny

View File

@@ -1518,7 +1518,6 @@ layouts:
map: Карта
basemap: Основа карты
layers: Слои
edit_custom_layers: Редактировать слои
cluster_options: Настройки кластеров
cluster_radius: Радиус кластера
cluster_minpoints: Минимальный размер кластера

View File

@@ -1370,7 +1370,6 @@ layouts:
map: Zemljevid
basemap: Osnovni zemljevid
layers: Plasti
edit_custom_layers: Uredi plasti
cluster_options: Možnosti gruče
cluster_radius: Polmer gruče
cluster_minpoints: Minimalna velikost gruče

View File

@@ -1485,7 +1485,6 @@ layouts:
map: 地图
basemap: 底图
layers: 图层
edit_custom_layers: 编辑图层
cluster_options: 集群选项
cluster_radius: 集群半径
cluster_minpoints: 集群最小尺寸

View File

@@ -8,7 +8,7 @@
<script lang="ts">
import 'maplibre-gl/dist/maplibre-gl.css';
import {
import maplibre, {
MapboxGeoJSONFeature,
MapLayerMouseEvent,
AttributionControl,
@@ -24,6 +24,7 @@ import {
import MapboxGeocoder from '@mapbox/mapbox-gl-geocoder';
import '@mapbox/mapbox-gl-geocoder/dist/mapbox-gl-geocoder.css';
import { ref, watch, PropType, onMounted, onUnmounted, defineComponent, toRefs, computed, WatchStopHandle } from 'vue';
import { useI18n } from 'vue-i18n';
import getSetting from '@/utils/get-setting';
import { useAppStore } from '@/stores';
@@ -64,6 +65,7 @@ export default defineComponent({
},
emits: ['moveend', 'featureclick', 'featureselect', 'fitdata', 'updateitempopup'],
setup(props, { emit }) {
const { t } = useI18n();
const appStore = useAppStore();
let map: Map;
const hoveredFeature = ref<MapboxGeoJSONFeature>();
@@ -90,7 +92,6 @@ export default defineComponent({
const boxSelectControl = new BoxSelectControl({
boxElementClass: 'map-selection-box',
selectButtonClass: 'mapboxgl-ctrl-select',
unselectButtonClass: 'mapboxgl-ctrl-unselect',
layers: ['__directus_polygons', '__directus_points', '__directus_lines'],
});
let geocoderControl: MapboxGeocoder | undefined;
@@ -102,6 +103,8 @@ export default defineComponent({
collapsed: true,
marker: { element: marker } as any,
flyTo: { speed: 1.4 },
mapboxgl: maplibre as any,
placeholder: t('layouts.map.find_location'),
});
}
onMounted(() => {
@@ -176,7 +179,7 @@ export default defineComponent({
}
function fitBounds() {
const bbox = props.data.bbox?.map((x) => x % 90);
const bbox = props.data.bbox;
if (map && bbox) {
map.fitBounds(bbox as LngLatBoundsLike, {
padding: 100,
@@ -247,7 +250,6 @@ export default defineComponent({
newSelection?.forEach((id) => {
map.setFeatureState({ id, source: '__directus' }, { selected: true });
});
boxSelectControl.showUnselect(newSelection?.length);
}
function onFeatureClick(event: MapLayerMouseEvent) {

View File

@@ -7,7 +7,7 @@ import { useI18n } from 'vue-i18n';
import { toRefs, computed, ref, watch } from 'vue';
import { toGeoJSON } from '@/utils/geometry';
import { layers } from './style';
import { layers as directusLayers } from './style';
import { useRouter } from 'vue-router';
import { useSync } from '@directus/shared/composables';
import { LayoutOptions, LayoutQuery } from './types';
@@ -59,12 +59,8 @@ export default defineLayout<LayoutOptions, LayoutQuery>({
};
});
const customLayerDrawerOpen = ref(false);
const displayTemplate = syncRefProperty(layoutOptions, 'displayTemplate', undefined);
const cameraOptions = syncRefProperty(layoutOptions, 'cameraOptions', undefined);
const customLayers = syncRefProperty(layoutOptions, 'customLayers', layers);
const autoLocationFilter = syncRefProperty(layoutOptions, 'autoLocationFilter', false);
const clusterData = syncRefProperty(layoutOptions, 'clusterData', false);
const geometryField = syncRefProperty(layoutOptions, 'geometryField', undefined);
const geometryFormat = computed<GeometryFormat | undefined>({
@@ -130,8 +126,6 @@ export default defineLayout<LayoutOptions, LayoutQuery>({
.filter((e) => !!e) as string[];
});
const locationFilterOutdated = ref(false);
function getLocationFilter(): Filter | undefined {
if (!isGeometryFieldNative.value || !cameraOptions.value || !geometryField.value) {
return;
@@ -157,49 +151,24 @@ export default defineLayout<LayoutOptions, LayoutQuery>({
} as Filter;
}
function updateLocationFilter() {
locationFilterOutdated.value = false;
locationFilter.value = getLocationFilter();
}
const shouldUpdateCamera = ref(false);
function clearLocationFilter() {
function fitDataBounds() {
shouldUpdateCamera.value = true;
locationFilterOutdated.value = false;
locationFilter.value = undefined;
}
function fitGeoJSONBounds() {
if (!geojson.value?.features.length) {
if (isGeometryFieldNative.value) {
locationFilter.value = undefined;
return;
}
shouldUpdateCamera.value = true;
locationFilterOutdated.value = false;
if (geojson.value) {
if (geojson.value?.features.length) {
geojsonBounds.value = cloneDeep(geojson.value.bbox);
}
}
function clearDataFilters() {
props?.clearFilters?.();
}
const shouldUpdateCamera = ref(false);
watch(
() => cameraOptions.value,
() => {
shouldUpdateCamera.value = false;
locationFilterOutdated.value = true;
if (autoLocationFilter.value) {
updateLocationFilter();
}
}
);
watch(
() => autoLocationFilter.value,
(value) => {
if (value) updateLocationFilter();
locationFilter.value = getLocationFilter();
}
);
@@ -251,7 +220,6 @@ export default defineLayout<LayoutOptions, LayoutQuery>({
}
}
const directusLayers = ref(layers);
const directusSource = ref({
type: 'geojson',
data: {
@@ -261,17 +229,6 @@ export default defineLayout<LayoutOptions, LayoutQuery>({
});
watch(() => clusterData.value, updateSource, { immediate: true });
updateLayers();
function updateLayers() {
customLayerDrawerOpen.value = false;
directusLayers.value = customLayers.value ?? [];
}
function resetLayers() {
directusLayers.value = cloneDeep(layers);
customLayers.value = directusLayers.value;
}
function updateSource() {
directusSource.value = merge({}, directusSource.value, {
@@ -340,9 +297,6 @@ export default defineLayout<LayoutOptions, LayoutQuery>({
geojson,
directusSource,
directusLayers,
customLayers,
updateLayers,
resetLayers,
featureId,
geojsonBounds,
geojsonLoading,
@@ -355,7 +309,6 @@ export default defineLayout<LayoutOptions, LayoutQuery>({
displayTemplate,
isGeometryFieldNative,
cameraOptions,
autoLocationFilter,
clusterData,
items,
loading,
@@ -374,13 +327,7 @@ export default defineLayout<LayoutOptions, LayoutQuery>({
refresh,
resetPresetAndRefresh,
geometryFields,
customLayerDrawerOpen,
locationFilterOutdated,
updateLocationFilter,
clearLocationFilter,
clearDataFilters,
locationFilter,
fitGeoJSONBounds,
fitDataBounds,
template,
itemPopup,
updateItemPopup,

View File

@@ -14,7 +14,7 @@
@featureclick="handleClick"
@featureselect="handleSelect"
@moveend="cameraOptionsWritable = $event"
@fitdata="fitGeoJSONBounds"
@fitdata="fitDataBounds"
@updateitempopup="updateItemPopup"
/>
@@ -26,15 +26,6 @@
<render-template :template="template" :item="itemPopup.item" :collection="collection" />
</div>
<v-button
v-if="isGeometryFieldNative && !autoLocationFilter && locationFilterOutdatedWritable"
small
class="location-filter"
@click="updateLocationFilter"
>
{{ t('layouts.map.search_this_area') }}
</v-button>
<transition name="fade">
<v-info v-if="error" type="danger" :title="t('unexpected_error')" icon="error" center>
{{ t('unexpected_error_copy') }}
@@ -55,23 +46,6 @@
{{ geojsonError }}
</v-info>
<v-progress-circular v-else-if="loading || geojsonLoading" indeterminate x-large class="center" />
<v-info
v-else-if="!loading && !itemCount && !locationFilterOutdated && (search || filter || locationFilter)"
icon="search"
center
:title="t('layouts.map.no_results_here')"
>
<template #append>
<v-card-actions>
<v-button :disabled="!search && !filter" @click="clearDataFilters">
{{ t('layouts.map.clear_data_filter') }}
</v-button>
<v-button :disabled="!locationFilter" @click="clearLocationFilter">
{{ t('layouts.map.clear_location_filter') }}
</v-button>
</v-card-actions>
</template>
</v-info>
</transition>
<template v-if="loading || itemCount > 0">
@@ -124,7 +98,6 @@ import { defineComponent, PropType } from 'vue';
import MapComponent from './components/map.vue';
import { useSync } from '@directus/shared/composables';
import { GeometryOptions, Item } from '@directus/shared/types';
import { Filter } from '@directus/shared/types';
export default defineComponent({
components: { MapComponent },
@@ -138,10 +111,6 @@ export default defineComponent({
type: Array as PropType<Item[]>,
default: () => [],
},
search: {
type: String as PropType<string | null>,
default: null,
},
loading: {
type: Boolean,
required: true,
@@ -222,38 +191,10 @@ export default defineComponent({
type: Boolean,
default: undefined,
},
locationFilterOutdated: {
type: Boolean,
required: true,
},
fitGeoJSONBounds: {
fitDataBounds: {
type: Function as PropType<() => void>,
required: true,
},
updateLocationFilter: {
type: Function as PropType<() => void>,
required: true,
},
clearDataFilters: {
type: Function as PropType<() => void>,
required: true,
},
clearLocationFilter: {
type: Function as PropType<() => void>,
required: true,
},
isGeometryFieldNative: {
type: Boolean,
required: true,
},
filter: {
type: Object as PropType<Filter>,
default: null,
},
locationFilter: {
type: Object as PropType<Filter>,
default: null,
},
template: {
type: String,
default: () => undefined,
@@ -267,15 +208,14 @@ export default defineComponent({
required: true,
},
},
emits: ['update:cameraOptions', 'update:limit', 'update:locationFilterOutdated'],
emits: ['update:cameraOptions', 'update:limit'],
setup(props, { emit }) {
const { t, n } = useI18n();
const cameraOptionsWritable = useSync(props, 'cameraOptions', emit);
const limitWritable = useSync(props, 'limit', emit);
const locationFilterOutdatedWritable = useSync(props, 'locationFilterOutdated', emit);
return { t, n, cameraOptionsWritable, limitWritable, locationFilterOutdatedWritable };
return { t, n, cameraOptionsWritable, limitWritable };
},
});
</script>
@@ -338,8 +278,8 @@ export default defineComponent({
background-color: var(--background-page);
border-radius: var(--border-radius);
box-shadow: var(--card-shadow);
transform: translate(-50%, -140%);
pointer-events: none;
translate: -50% calc(-100% - 12px);
}
.mapboxgl-ctrl-dropdown {

View File

@@ -21,14 +21,10 @@
<div class="field">
<div class="type-label">{{ t('display_template') }}</div>
<v-field-template v-model="displayTemplateWritable" :collection="collection" />
</div>
<div class="field">
<v-checkbox
v-model="autoLocationFilterWritable"
:label="t('layouts.map.auto_location_filter')"
:disabled="geometryOptions && geometryOptions.geometryFormat !== 'native'"
<v-field-template
v-model="displayTemplateWritable"
:collection="collection"
:placeholder="t('layouts.map.default_template')"
/>
</div>
@@ -65,10 +61,6 @@ export default defineComponent({
type: String,
default: undefined,
},
autoLocationFilter: {
type: Boolean,
default: undefined,
},
geometryOptions: {
type: Object as PropType<GeometryOptions>,
default: undefined,
@@ -77,44 +69,19 @@ export default defineComponent({
type: Boolean,
default: undefined,
},
customLayerDrawerOpen: {
type: Boolean,
required: true,
},
resetLayers: {
type: Function as PropType<() => void>,
required: true,
},
updateLayers: {
type: Function as PropType<() => void>,
required: true,
},
customLayers: {
type: Array as PropType<any[]>,
default: undefined,
},
displayTemplate: {
type: String as string | undefined,
default: undefined,
},
},
emits: [
'update:geometryField',
'update:autoLocationFilter',
'update:clusterData',
'update:customLayerDrawerOpen',
'update:customLayers',
],
emits: ['update:geometryField', 'update:autoLocationFilter', 'update:clusterData'],
setup(props, { emit }) {
const { t } = useI18n();
const appStore = useAppStore();
const geometryFieldWritable = useSync(props, 'geometryField', emit);
const autoLocationFilterWritable = useSync(props, 'autoLocationFilter', emit);
const clusterDataWritable = useSync(props, 'clusterData', emit);
const customLayerDrawerOpenWritable = useSync(props, 'customLayerDrawerOpen', emit);
const customLayersWritable = useSync(props, 'customLayers', emit);
const displayTemplateWritable = useSync(props, 'displayTemplate', emit);
const basemaps = getBasemapSources();
@@ -123,10 +90,7 @@ export default defineComponent({
return {
t,
geometryFieldWritable,
autoLocationFilterWritable,
clusterDataWritable,
customLayerDrawerOpenWritable,
customLayersWritable,
displayTemplateWritable,
basemaps,
basemap,

View File

@@ -1,4 +1,4 @@
import { CameraOptions, AnyLayer } from 'maplibre-gl';
import { CameraOptions } from 'maplibre-gl';
import { GeometryFormat } from '@directus/shared/types';
export type LayoutQuery = {
@@ -10,7 +10,6 @@ export type LayoutQuery = {
export type LayoutOptions = {
cameraOptions?: CameraOptions & { bbox: any };
customLayers?: Array<AnyLayer>;
geometryFormat?: GeometryFormat;
geometryField?: string;
autoLocationFilter?: boolean;

View File

@@ -113,6 +113,7 @@
font-family: inherit !important;
line-height: inherit !important;
background-color: var(--background-page);
overflow: hidden;
&,
&.suggestions {

View File

@@ -7,7 +7,7 @@ export class ButtonControl {
constructor(private className: string, private callback: (...args: any) => any) {
this.element = document.createElement('button');
this.element.className = this.className;
this.element.onclick = callback;
this.element.onpointerdown = callback;
this.active = false;
}
click(...args: any[]): void {
@@ -36,7 +36,6 @@ type BoxSelectControlOptions = {
groupElementClass?: string;
boxElementClass?: string;
selectButtonClass?: string;
unselectButtonClass?: string;
layers: string[];
};
@@ -45,7 +44,6 @@ export class BoxSelectControl {
boxElement: HTMLElement;
selectButton: ButtonControl;
unselectButton: ButtonControl;
map?: Map & { fire: (event: string, data?: any) => void };
layers: string[];
@@ -70,13 +68,7 @@ export class BoxSelectControl {
this.selectButton = new ButtonControl(options?.selectButtonClass ?? 'ctrl-select', () => {
this.activate(!this.shiftPressed);
});
this.unselectButton = new ButtonControl(options?.unselectButtonClass ?? 'ctrl-unselect', () => {
this.reset();
this.activate(false);
this.map!.fire('select.end', { features: [] });
});
this.groupElement.appendChild(this.selectButton.element);
this.groupElement.appendChild(this.unselectButton.element);
this.onKeyDownHandler = this.onKeyDown.bind(this);
this.onKeyUpHandler = this.onKeyUp.bind(this);
@@ -132,10 +124,6 @@ export class BoxSelectControl {
this.map!.fire(`select.${yes ? 'enable' : 'disable'}`);
}
showUnselect(yes: boolean): void {
this.unselectButton.show(yes);
}
onKeyUp(event: KeyboardEvent): void {
if (event.key == 'Shift') {
this.activate(false);
@@ -171,6 +159,9 @@ export class BoxSelectControl {
onMouseUp(event: MouseEvent): void {
this.reset();
if (!this.active()) {
return;
}
const features = this.map!.queryRenderedFeatures([this.startPos!, this.lastPos!], {
layers: this.layers,
});