mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
Geomap: Add dynamic initial view options (#54419)
* Geomap: Add dynamic initial view options * Add control options for dynamic initial view * Add handling for last only scope * Remove stale todos * Only reinitialize map view during data if fit * Add options for data fit In map init, remove dependency on layers input. Add a boolean to map view config to handle all layers, with default set to true. Also, add layer string to handle currently selected layer. Change some verbage. In map view editor, add controls for data extent options. Only display layer selection when all layers is not selected. Update layer extent function to handle all options permutations. When all layers is selected, return all data for extent calculation. When last only is selected, only return last data point in matching layer for extent calculation. Otherwise, return all data points in matching layer for extent calculation. * Change padding tooltip and hide for last only * Simplify getLayersExtent call * Add enums for data scope options * Update GeomapPanel for refactor merge * Move view init functions back into geomap class Re-apply data change handling and extent calculation handling. * Update padding tooltip verbage * Ensure geomap panel options layers are initialized * Clean up GeomapPanel file (betterer) * refactors / clean up * more cleanup Co-authored-by: nmarrs <nathanielmarrs@gmail.com>
This commit is contained in:
parent
5be04f5336
commit
6e85dfa25a
@ -4,7 +4,10 @@ import { Map as OpenLayersMap, MapBrowserEvent, View } from 'ol';
|
||||
import Attribution from 'ol/control/Attribution';
|
||||
import ScaleLine from 'ol/control/ScaleLine';
|
||||
import Zoom from 'ol/control/Zoom';
|
||||
import { Coordinate } from 'ol/coordinate';
|
||||
import { isEmpty } from 'ol/extent';
|
||||
import MouseWheelZoom from 'ol/interaction/MouseWheelZoom';
|
||||
import { fromLonLat } from 'ol/proj';
|
||||
import React, { Component, ReactNode } from 'react';
|
||||
import { Subscription } from 'rxjs';
|
||||
|
||||
@ -22,12 +25,13 @@ import { GeomapHoverPayload } from './event';
|
||||
import { getGlobalStyles } from './globalStyles';
|
||||
import { defaultMarkersConfig } from './layers/data/markersLayer';
|
||||
import { DEFAULT_BASEMAP_CONFIG } from './layers/registry';
|
||||
import { ControlsOptions, GeomapPanelOptions, MapLayerState, TooltipMode } from './types';
|
||||
import { ControlsOptions, GeomapPanelOptions, MapLayerState, MapViewConfig, TooltipMode } from './types';
|
||||
import { getActions } from './utils/actions';
|
||||
import { getLayersExtent } from './utils/getLayersExtent';
|
||||
import { applyLayerFilter, initLayer } from './utils/layers';
|
||||
import { pointerClickListener, pointerMoveListener, setTooltipListeners } from './utils/tootltip';
|
||||
import { updateMap, getNewOpenLayersMap, notifyPanelEditor } from './utils/utils';
|
||||
import { initMapView, initViewExtent } from './utils/view';
|
||||
import { centerPointRegistry, MapCenterID } from './view';
|
||||
|
||||
// Allows multiple panels to share the same view instance
|
||||
let sharedView: View | undefined = undefined;
|
||||
@ -143,10 +147,12 @@ export class GeomapPanel extends Component<Props, State> {
|
||||
optionsChanged(options: GeomapPanelOptions) {
|
||||
const oldOptions = this.props.options;
|
||||
if (options.view !== oldOptions.view) {
|
||||
const [updatedSharedView, view] = initMapView(options.view, sharedView, this.map!.getLayers());
|
||||
const [updatedSharedView, view] = this.initMapView(options.view, sharedView);
|
||||
sharedView = updatedSharedView;
|
||||
// eslint-disable-next-line
|
||||
this.map!.setView(view as View);
|
||||
|
||||
if (this.map && view) {
|
||||
this.map.setView(view);
|
||||
}
|
||||
}
|
||||
|
||||
if (options.controls !== oldOptions.controls) {
|
||||
@ -164,6 +170,16 @@ export class GeomapPanel extends Component<Props, State> {
|
||||
applyLayerFilter(state.handler, state.options, this.props.data);
|
||||
}
|
||||
}
|
||||
|
||||
// Because data changed, check map view and change if needed (data fit)
|
||||
const v = centerPointRegistry.getIfExists(this.props.options.view.id);
|
||||
if (v && v.id === MapCenterID.Fit) {
|
||||
const [, view] = this.initMapView(this.props.options.view);
|
||||
|
||||
if (this.map && view) {
|
||||
this.map.setView(view);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
initMapRef = async (div: HTMLDivElement) => {
|
||||
@ -173,8 +189,7 @@ export class GeomapPanel extends Component<Props, State> {
|
||||
}
|
||||
|
||||
if (!div) {
|
||||
// eslint-disable-next-line
|
||||
this.map = undefined as unknown as OpenLayersMap;
|
||||
this.map = undefined;
|
||||
return;
|
||||
}
|
||||
const { options } = this.props;
|
||||
@ -187,13 +202,15 @@ export class GeomapPanel extends Component<Props, State> {
|
||||
layers.push(await initLayer(this, map, options.basemap ?? DEFAULT_BASEMAP_CONFIG, true));
|
||||
|
||||
// Default layer values
|
||||
const layerOptions = options.layers ?? [defaultMarkersConfig];
|
||||
if (!options.layers) {
|
||||
options.layers = [defaultMarkersConfig];
|
||||
}
|
||||
|
||||
for (const lyr of layerOptions) {
|
||||
for (const lyr of options.layers) {
|
||||
layers.push(await initLayer(this, map, lyr, false));
|
||||
}
|
||||
} catch (ex) {
|
||||
console.error('error loading layers', ex); // eslint-disable-line no-console
|
||||
console.error('error loading layers', ex);
|
||||
}
|
||||
|
||||
for (const lyr of layers) {
|
||||
@ -201,7 +218,7 @@ export class GeomapPanel extends Component<Props, State> {
|
||||
}
|
||||
this.layers = layers;
|
||||
this.map = map; // redundant
|
||||
initViewExtent(map.getView(), options.view, map.getLayers());
|
||||
this.initViewExtent(map.getView(), options.view);
|
||||
|
||||
this.mouseWheelZoom = new MouseWheelZoom();
|
||||
this.map?.addInteraction(this.mouseWheelZoom);
|
||||
@ -231,6 +248,70 @@ export class GeomapPanel extends Component<Props, State> {
|
||||
pointerMoveListener(evt, this);
|
||||
};
|
||||
|
||||
initMapView = (config: MapViewConfig, sharedView?: View | undefined): Array<View | undefined> => {
|
||||
let view = new View({
|
||||
center: [0, 0],
|
||||
zoom: 1,
|
||||
showFullExtent: true, // allows zooming so the full range is visible
|
||||
});
|
||||
|
||||
// With shared views, all panels use the same view instance
|
||||
if (config.shared) {
|
||||
if (!sharedView) {
|
||||
sharedView = view;
|
||||
} else {
|
||||
view = sharedView;
|
||||
}
|
||||
}
|
||||
this.initViewExtent(view, config);
|
||||
|
||||
return [sharedView, view];
|
||||
};
|
||||
|
||||
initViewExtent(view: View, config: MapViewConfig) {
|
||||
const v = centerPointRegistry.getIfExists(config.id);
|
||||
if (v) {
|
||||
let coord: Coordinate | undefined = undefined;
|
||||
if (v.lat == null) {
|
||||
if (v.id === MapCenterID.Coordinates) {
|
||||
coord = [config.lon ?? 0, config.lat ?? 0];
|
||||
} else if (v.id === MapCenterID.Fit) {
|
||||
const extent = getLayersExtent(this.layers, config.allLayers, config.lastOnly, config.layer);
|
||||
if (!isEmpty(extent)) {
|
||||
const padding = config.padding ?? 5;
|
||||
const res = view.getResolutionForExtent(extent, this.map?.getSize());
|
||||
const maxZoom = config.zoom ?? config.maxZoom;
|
||||
view.fit(extent, {
|
||||
maxZoom: maxZoom,
|
||||
});
|
||||
view.setResolution(res * (padding / 100 + 1));
|
||||
const adjustedZoom = view.getZoom();
|
||||
if (adjustedZoom && maxZoom && adjustedZoom > maxZoom) {
|
||||
view.setZoom(maxZoom);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// TODO: view requires special handling
|
||||
}
|
||||
} else {
|
||||
coord = [v.lon ?? 0, v.lat ?? 0];
|
||||
}
|
||||
if (coord) {
|
||||
view.setCenter(fromLonLat(coord));
|
||||
}
|
||||
}
|
||||
|
||||
if (config.maxZoom) {
|
||||
view.setMaxZoom(config.maxZoom);
|
||||
}
|
||||
if (config.minZoom) {
|
||||
view.setMaxZoom(config.minZoom);
|
||||
}
|
||||
if (config.zoom && v?.id !== MapCenterID.Fit) {
|
||||
view.setZoom(config.zoom);
|
||||
}
|
||||
}
|
||||
|
||||
initControls(options: ControlsOptions) {
|
||||
if (!this.map) {
|
||||
return;
|
||||
|
@ -0,0 +1,37 @@
|
||||
import React from 'react';
|
||||
|
||||
import { InlineFieldRow, InlineField } from '@grafana/ui';
|
||||
import { NumberInput } from 'app/core/components/OptionsUI/NumberInput';
|
||||
|
||||
import { MapViewConfig } from '../types';
|
||||
|
||||
type Props = {
|
||||
labelWidth: number;
|
||||
value: MapViewConfig;
|
||||
onChange: (value?: MapViewConfig | undefined) => void;
|
||||
};
|
||||
|
||||
export const CoordinatesMapViewEditor = ({ labelWidth, value, onChange }: Props) => {
|
||||
const onLatitudeChange = (latitude: number | undefined) => {
|
||||
onChange({ ...value, lat: latitude });
|
||||
};
|
||||
|
||||
const onLongitudeChange = (longitude: number | undefined) => {
|
||||
onChange({ ...value, lon: longitude });
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<InlineFieldRow>
|
||||
<InlineField label="Latitude" labelWidth={labelWidth} grow={true}>
|
||||
<NumberInput value={value.lat} min={-90} max={90} step={0.001} onChange={onLatitudeChange} />
|
||||
</InlineField>
|
||||
</InlineFieldRow>
|
||||
<InlineFieldRow>
|
||||
<InlineField label="Longitude" labelWidth={labelWidth} grow={true}>
|
||||
<NumberInput value={value.lon} min={-180} max={180} step={0.001} onChange={onLongitudeChange} />
|
||||
</InlineField>
|
||||
</InlineFieldRow>
|
||||
</>
|
||||
);
|
||||
};
|
117
public/app/plugins/panel/geomap/editor/FitMapViewEditor.tsx
Normal file
117
public/app/plugins/panel/geomap/editor/FitMapViewEditor.tsx
Normal file
@ -0,0 +1,117 @@
|
||||
import React, { useCallback, useMemo } from 'react';
|
||||
|
||||
import { SelectableValue, StandardEditorContext } from '@grafana/data';
|
||||
import { InlineFieldRow, InlineField, RadioButtonGroup, Select } from '@grafana/ui';
|
||||
import { NumberInput } from 'app/core/components/OptionsUI/NumberInput';
|
||||
|
||||
import { GeomapInstanceState, GeomapPanelOptions, MapViewConfig } from '../types';
|
||||
|
||||
type Props = {
|
||||
labelWidth: number;
|
||||
value: MapViewConfig;
|
||||
onChange: (value?: MapViewConfig | undefined) => void;
|
||||
context: StandardEditorContext<GeomapPanelOptions, GeomapInstanceState>;
|
||||
};
|
||||
|
||||
// Data scope options for 'Fit to data'
|
||||
enum DataScopeValues {
|
||||
all = 'all',
|
||||
layer = 'layer',
|
||||
last = 'last',
|
||||
}
|
||||
enum DataScopeLabels {
|
||||
all = 'All layers',
|
||||
layer = 'Layer',
|
||||
last = 'Last value',
|
||||
}
|
||||
|
||||
const ScopeOptions = Object.values(DataScopeValues);
|
||||
|
||||
const DataScopeOptions: Array<SelectableValue<DataScopeValues>> = ScopeOptions.map((dataScopeOption) => ({
|
||||
label: DataScopeLabels[dataScopeOption],
|
||||
value: dataScopeOption,
|
||||
}));
|
||||
|
||||
export const FitMapViewEditor = ({ labelWidth, value, onChange, context }: Props) => {
|
||||
const layers = useMemo(() => {
|
||||
if (context.options?.layers) {
|
||||
return context.options.layers.map((layer) => ({
|
||||
label: layer.name,
|
||||
value: layer.name,
|
||||
description: undefined,
|
||||
}));
|
||||
}
|
||||
return [];
|
||||
}, [context.options?.layers]);
|
||||
|
||||
const onSelectLayer = useCallback(
|
||||
(selection: SelectableValue<string>) => {
|
||||
onChange({ ...value, layer: selection.value });
|
||||
},
|
||||
[value, onChange]
|
||||
);
|
||||
|
||||
const allLayersEditorFragment = (
|
||||
<InlineFieldRow>
|
||||
<InlineField label="Layer" labelWidth={labelWidth} grow={true}>
|
||||
<Select options={layers} onChange={onSelectLayer} placeholder={layers[0]?.label} />
|
||||
</InlineField>
|
||||
</InlineFieldRow>
|
||||
);
|
||||
|
||||
const onChangePadding = (padding: number | undefined) => {
|
||||
onChange({ ...value, padding: padding });
|
||||
};
|
||||
|
||||
const lastOnlyEditorFragment = (
|
||||
<InlineFieldRow>
|
||||
<InlineField
|
||||
label="Padding"
|
||||
labelWidth={labelWidth}
|
||||
grow={true}
|
||||
tooltip="sets padding in relative percent beyond data extent"
|
||||
>
|
||||
<NumberInput value={value?.padding ?? 5} min={0} step={1} onChange={onChangePadding} />
|
||||
</InlineField>
|
||||
</InlineFieldRow>
|
||||
);
|
||||
|
||||
const currentDataScope = value.allLayers
|
||||
? DataScopeValues.all
|
||||
: !value.allLayers && value.lastOnly
|
||||
? DataScopeValues.last
|
||||
: DataScopeValues.layer;
|
||||
|
||||
const onDataScopeChange = (dataScope: DataScopeValues) => {
|
||||
if (dataScope !== DataScopeValues.all && !value.layer) {
|
||||
onChange({
|
||||
...value,
|
||||
allLayers: dataScope === String(DataScopeValues.all),
|
||||
lastOnly: dataScope === String(DataScopeValues.last),
|
||||
layer: layers[0].value,
|
||||
});
|
||||
} else {
|
||||
onChange({
|
||||
...value,
|
||||
allLayers: dataScope === String(DataScopeValues.all),
|
||||
lastOnly: dataScope === String(DataScopeValues.last),
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<InlineFieldRow>
|
||||
<InlineField label="Data" labelWidth={labelWidth} grow={true}>
|
||||
<RadioButtonGroup
|
||||
value={currentDataScope}
|
||||
options={DataScopeOptions}
|
||||
onChange={onDataScopeChange}
|
||||
></RadioButtonGroup>
|
||||
</InlineField>
|
||||
</InlineFieldRow>
|
||||
{!value?.allLayers && allLayersEditorFragment}
|
||||
{!value?.lastOnly && lastOnlyEditorFragment}
|
||||
</>
|
||||
);
|
||||
};
|
@ -1,5 +1,5 @@
|
||||
import { toLonLat } from 'ol/proj';
|
||||
import React, { FC, useMemo, useCallback } from 'react';
|
||||
import React, { useMemo, useCallback } from 'react';
|
||||
|
||||
import { StandardEditorProps, SelectableValue } from '@grafana/data';
|
||||
import { Button, InlineField, InlineFieldRow, Select, VerticalGroup } from '@grafana/ui';
|
||||
@ -8,9 +8,14 @@ import { NumberInput } from 'app/core/components/OptionsUI/NumberInput';
|
||||
import { GeomapPanelOptions, MapViewConfig, GeomapInstanceState } from '../types';
|
||||
import { centerPointRegistry, MapCenterID } from '../view';
|
||||
|
||||
export const MapViewEditor: FC<
|
||||
StandardEditorProps<MapViewConfig, unknown, GeomapPanelOptions, GeomapInstanceState>
|
||||
> = ({ value, onChange, context }) => {
|
||||
import { CoordinatesMapViewEditor } from './CoordinatesMapViewEditor';
|
||||
import { FitMapViewEditor } from './FitMapViewEditor';
|
||||
|
||||
export const MapViewEditor = ({
|
||||
value,
|
||||
onChange,
|
||||
context,
|
||||
}: StandardEditorProps<MapViewConfig, unknown, GeomapPanelOptions, GeomapInstanceState>) => {
|
||||
const labelWidth = 10;
|
||||
|
||||
const views = useMemo(() => {
|
||||
@ -64,39 +69,15 @@ export const MapViewEditor: FC<
|
||||
<Select options={views.options} value={views.current} onChange={onSelectView} />
|
||||
</InlineField>
|
||||
</InlineFieldRow>
|
||||
{value?.id === MapCenterID.Coordinates && (
|
||||
<>
|
||||
<InlineFieldRow>
|
||||
<InlineField label="Latitude" labelWidth={labelWidth} grow={true}>
|
||||
<NumberInput
|
||||
value={value.lat}
|
||||
min={-90}
|
||||
max={90}
|
||||
step={0.001}
|
||||
onChange={(v) => {
|
||||
onChange({ ...value, lat: v });
|
||||
}}
|
||||
/>
|
||||
</InlineField>
|
||||
</InlineFieldRow>
|
||||
<InlineFieldRow>
|
||||
<InlineField label="Longitude" labelWidth={labelWidth} grow={true}>
|
||||
<NumberInput
|
||||
value={value.lon}
|
||||
min={-180}
|
||||
max={180}
|
||||
step={0.001}
|
||||
onChange={(v) => {
|
||||
onChange({ ...value, lon: v });
|
||||
}}
|
||||
/>
|
||||
</InlineField>
|
||||
</InlineFieldRow>
|
||||
</>
|
||||
{value.id === MapCenterID.Coordinates && (
|
||||
<CoordinatesMapViewEditor labelWidth={labelWidth} value={value} onChange={onChange} />
|
||||
)}
|
||||
{value.id === MapCenterID.Fit && (
|
||||
<FitMapViewEditor labelWidth={labelWidth} value={value} onChange={onChange} context={context} />
|
||||
)}
|
||||
|
||||
<InlineFieldRow>
|
||||
<InlineField label="Zoom" labelWidth={labelWidth} grow={true}>
|
||||
<InlineField label={value?.id === MapCenterID.Fit ? 'Max Zoom' : 'Zoom'} labelWidth={labelWidth} grow={true}>
|
||||
<NumberInput
|
||||
value={value?.zoom ?? 1}
|
||||
min={1}
|
||||
|
@ -48,6 +48,10 @@ export interface MapViewConfig {
|
||||
zoom?: number;
|
||||
minZoom?: number;
|
||||
maxZoom?: number;
|
||||
padding?: number;
|
||||
allLayers?: boolean;
|
||||
lastOnly?: boolean;
|
||||
layer?: string;
|
||||
shared?: boolean;
|
||||
}
|
||||
|
||||
@ -56,6 +60,7 @@ export const defaultView: MapViewConfig = {
|
||||
lat: 0,
|
||||
lon: 0,
|
||||
zoom: 1,
|
||||
allLayers: true,
|
||||
};
|
||||
|
||||
/** Support hide from legend/tooltip */
|
||||
|
@ -1,18 +1,39 @@
|
||||
import { Collection } from 'ol';
|
||||
import { createEmpty, extend, Extent } from 'ol/extent';
|
||||
import BaseLayer from 'ol/layer/Base';
|
||||
import LayerGroup from 'ol/layer/Group';
|
||||
import VectorLayer from 'ol/layer/Vector';
|
||||
|
||||
export function getLayersExtent(layers: Collection<BaseLayer>): Extent {
|
||||
import { MapLayerState } from '../types';
|
||||
|
||||
export function getLayersExtent(
|
||||
layers: MapLayerState[] = [],
|
||||
allLayers = false,
|
||||
lastOnly = false,
|
||||
layer: string | undefined
|
||||
): Extent {
|
||||
return layers
|
||||
.getArray()
|
||||
.filter((l) => l instanceof VectorLayer || l instanceof LayerGroup)
|
||||
.flatMap((l) => {
|
||||
.filter((l) => l.layer instanceof VectorLayer || l.layer instanceof LayerGroup)
|
||||
.flatMap((ll) => {
|
||||
const l = ll.layer;
|
||||
if (l instanceof LayerGroup) {
|
||||
return getLayerGroupExtent(l);
|
||||
} else if (l instanceof VectorLayer) {
|
||||
return [l.getSource().getExtent()] ?? [];
|
||||
if (allLayers) {
|
||||
// Return everything from all layers
|
||||
return [l.getSource().getExtent()] ?? [];
|
||||
} else if (lastOnly && layer === ll.options.name) {
|
||||
// Return last only for selected layer
|
||||
const feat = l.getSource().getFeatures();
|
||||
const featOfInterest = feat[feat.length - 1];
|
||||
const geo = featOfInterest?.getGeometry();
|
||||
if (geo) {
|
||||
return [geo.getExtent()] ?? [];
|
||||
}
|
||||
return [];
|
||||
} else if (!lastOnly && layer === ll.options.name) {
|
||||
// Return all points for selected layer
|
||||
return [l.getSource().getExtent()] ?? [];
|
||||
}
|
||||
return [];
|
||||
} else {
|
||||
return [];
|
||||
}
|
||||
|
@ -10,8 +10,6 @@ import { GeomapPanel } from '../GeomapPanel';
|
||||
import { defaultStyleConfig, StyleConfig, StyleConfigState, StyleDimensions } from '../style/types';
|
||||
import { GeomapPanelOptions, MapLayerState } from '../types';
|
||||
|
||||
import { initMapView } from './view';
|
||||
|
||||
export function getStyleDimension(
|
||||
frame: DataFrame | undefined,
|
||||
style: StyleConfigState,
|
||||
@ -77,7 +75,7 @@ async function initGeojsonFiles() {
|
||||
}
|
||||
|
||||
export const getNewOpenLayersMap = (panel: GeomapPanel, options: GeomapPanelOptions, div: HTMLDivElement) => {
|
||||
const [view] = initMapView(options.view, undefined, undefined);
|
||||
const [view] = panel.initMapView(options.view, undefined);
|
||||
return (panel.map = new OpenLayersMap({
|
||||
view: view,
|
||||
pixelRatio: 1, // or zoom?
|
||||
|
@ -1,73 +0,0 @@
|
||||
import { View, Collection } from 'ol';
|
||||
import { Coordinate } from 'ol/coordinate';
|
||||
import { isEmpty } from 'ol/extent';
|
||||
import BaseLayer from 'ol/layer/Base';
|
||||
import { fromLonLat } from 'ol/proj';
|
||||
|
||||
import { MapViewConfig } from '../types';
|
||||
import { centerPointRegistry, MapCenterID } from '../view';
|
||||
|
||||
import { getLayersExtent } from './getLayersExtent';
|
||||
|
||||
export const initViewExtent = (view: View, config: MapViewConfig, layers: Collection<BaseLayer>) => {
|
||||
const v = centerPointRegistry.getIfExists(config.id);
|
||||
if (v) {
|
||||
let coord: Coordinate | undefined = undefined;
|
||||
if (v.lat == null) {
|
||||
if (v.id === MapCenterID.Coordinates) {
|
||||
coord = [config.lon ?? 0, config.lat ?? 0];
|
||||
} else if (v.id === MapCenterID.Fit) {
|
||||
const extent = getLayersExtent(layers);
|
||||
if (!isEmpty(extent)) {
|
||||
view.fit(extent, {
|
||||
padding: [30, 30, 30, 30],
|
||||
maxZoom: config.zoom ?? config.maxZoom,
|
||||
});
|
||||
}
|
||||
} else {
|
||||
// TODO: view requires special handling
|
||||
}
|
||||
} else {
|
||||
coord = [v.lon ?? 0, v.lat ?? 0];
|
||||
}
|
||||
if (coord) {
|
||||
view.setCenter(fromLonLat(coord));
|
||||
}
|
||||
}
|
||||
|
||||
if (config.maxZoom) {
|
||||
view.setMaxZoom(config.maxZoom);
|
||||
}
|
||||
if (config.minZoom) {
|
||||
view.setMaxZoom(config.minZoom);
|
||||
}
|
||||
if (config.zoom && v?.id !== MapCenterID.Fit) {
|
||||
view.setZoom(config.zoom);
|
||||
}
|
||||
};
|
||||
|
||||
export const initMapView = (
|
||||
config: MapViewConfig,
|
||||
sharedView?: View | undefined,
|
||||
layers?: Collection<BaseLayer>
|
||||
): Array<View | undefined> => {
|
||||
let view = new View({
|
||||
center: [0, 0],
|
||||
zoom: 1,
|
||||
showFullExtent: true, // allows zooming so the full range is visible
|
||||
});
|
||||
|
||||
// With shared views, all panels use the same view instance
|
||||
if (config.shared) {
|
||||
if (!sharedView) {
|
||||
sharedView = view;
|
||||
} else {
|
||||
view = sharedView;
|
||||
}
|
||||
}
|
||||
if (layers) {
|
||||
initViewExtent(view, config, layers);
|
||||
}
|
||||
|
||||
return [sharedView, view];
|
||||
};
|
@ -15,7 +15,7 @@ export enum MapCenterID {
|
||||
export const centerPointRegistry = new Registry<MapCenterItems>(() => [
|
||||
{
|
||||
id: MapCenterID.Fit as string,
|
||||
name: 'Fit data layers',
|
||||
name: 'Fit to data',
|
||||
zoom: 15, // max zoom
|
||||
},
|
||||
{
|
||||
|
Loading…
Reference in New Issue
Block a user