mirror of
https://github.com/grafana/grafana.git
synced 2025-02-11 16:15:42 -06:00
Geomap: improve the view configuration (#36893)
This commit is contained in:
parent
001331e2ac
commit
ee3a320540
@ -31,6 +31,7 @@ interface MapLayerState {
|
||||
|
||||
// Allows multiple panels to share the same view instance
|
||||
let sharedView: View | undefined = undefined;
|
||||
export let lastGeomapPanelInstance: GeomapPanel | undefined = undefined;
|
||||
|
||||
type Props = PanelProps<GeomapPanelOptions>;
|
||||
export class GeomapPanel extends Component<Props> {
|
||||
@ -43,6 +44,10 @@ export class GeomapPanel extends Component<Props> {
|
||||
style = getStyles(config.theme);
|
||||
overlayProps: OverlayProps = {};
|
||||
|
||||
componentDidMount() {
|
||||
lastGeomapPanelInstance = this;
|
||||
}
|
||||
|
||||
shouldComponentUpdate(nextProps: Props) {
|
||||
if (!this.map) {
|
||||
return true; // not yet initalized
|
||||
@ -206,13 +211,12 @@ export class GeomapPanel extends Component<Props> {
|
||||
}
|
||||
}
|
||||
|
||||
const v = centerPointRegistry.getIfExists(config.center.id);
|
||||
const v = centerPointRegistry.getIfExists(config.id);
|
||||
if (v) {
|
||||
let coord: Coordinate | undefined = undefined;
|
||||
if (v.lat == null) {
|
||||
if (v.id === MapCenterID.Coordinates) {
|
||||
const center = config.center ?? {};
|
||||
coord = [center.lon ?? 0, center.lat ?? 0];
|
||||
coord = [config.lon ?? 0, config.lat ?? 0];
|
||||
} else {
|
||||
console.log('TODO, view requires special handling', v);
|
||||
}
|
||||
|
@ -1,85 +0,0 @@
|
||||
import React, { FC, useMemo } from 'react';
|
||||
import { GrafanaTheme, StandardEditorProps } from '@grafana/data';
|
||||
import { Select, stylesFactory, useStyles } from '@grafana/ui';
|
||||
import { GeomapPanelOptions, MapCenterConfig } from '../types';
|
||||
import { centerPointRegistry, MapCenterID } from '../view';
|
||||
import { css } from '@emotion/css';
|
||||
import { NumberInput } from '../components/NumberInput';
|
||||
|
||||
export const MapCenterEditor: FC<StandardEditorProps<MapCenterConfig, any, GeomapPanelOptions>> = ({
|
||||
value,
|
||||
onChange,
|
||||
context,
|
||||
}) => {
|
||||
const style = useStyles(getStyles);
|
||||
|
||||
const views = useMemo(() => {
|
||||
const ids: string[] = [];
|
||||
if (value?.id) {
|
||||
ids.push(value.id);
|
||||
} else {
|
||||
ids.push(centerPointRegistry.list()[0].id);
|
||||
}
|
||||
return centerPointRegistry.selectOptions(ids);
|
||||
}, [value?.id]);
|
||||
|
||||
return (
|
||||
<div>
|
||||
<Select
|
||||
options={views.options}
|
||||
value={views.current}
|
||||
onChange={(v) => {
|
||||
onChange({
|
||||
id: v.value!,
|
||||
});
|
||||
}}
|
||||
/>
|
||||
{value?.id === MapCenterID.Coordinates && (
|
||||
<div>
|
||||
<table className={style.table}>
|
||||
<tbody>
|
||||
<tr>
|
||||
<th className={style.half}>Latitude</th>
|
||||
<th className={style.half}>Longitude</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<NumberInput
|
||||
value={value.lat}
|
||||
min={-90}
|
||||
max={90}
|
||||
placeholder="0"
|
||||
onChange={(v) => {
|
||||
onChange({ ...value, lat: v });
|
||||
}}
|
||||
/>
|
||||
</td>
|
||||
<td>
|
||||
<NumberInput
|
||||
value={value.lon}
|
||||
min={-180}
|
||||
max={180}
|
||||
placeholder="0"
|
||||
onChange={(v) => {
|
||||
onChange({ ...value, lon: v });
|
||||
}}
|
||||
/>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
const getStyles = stylesFactory((theme: GrafanaTheme) => ({
|
||||
table: css`
|
||||
width: 100%;
|
||||
margin-top: 8px;
|
||||
`,
|
||||
half: css`
|
||||
width: 50%;
|
||||
`,
|
||||
}));
|
120
public/app/plugins/panel/geomap/editor/MapViewEditor.tsx
Normal file
120
public/app/plugins/panel/geomap/editor/MapViewEditor.tsx
Normal file
@ -0,0 +1,120 @@
|
||||
import React, { FC, useMemo, useCallback } from 'react';
|
||||
import { StandardEditorProps, SelectableValue } from '@grafana/data';
|
||||
import { Button, InlineField, InlineFieldRow, Select, VerticalGroup } from '@grafana/ui';
|
||||
import { GeomapPanelOptions, MapViewConfig } from '../types';
|
||||
import { centerPointRegistry, MapCenterID } from '../view';
|
||||
import { NumberInput } from '../components/NumberInput';
|
||||
import { lastGeomapPanelInstance } from '../GeomapPanel';
|
||||
import { toLonLat } from 'ol/proj';
|
||||
|
||||
export const MapViewEditor: FC<StandardEditorProps<MapViewConfig, any, GeomapPanelOptions>> = ({
|
||||
value,
|
||||
onChange,
|
||||
context,
|
||||
}) => {
|
||||
const labelWidth = 10;
|
||||
|
||||
const views = useMemo(() => {
|
||||
const ids: string[] = [];
|
||||
if (value?.id) {
|
||||
ids.push(value.id);
|
||||
} else {
|
||||
ids.push(centerPointRegistry.list()[0].id);
|
||||
}
|
||||
return centerPointRegistry.selectOptions(ids);
|
||||
}, [value?.id]);
|
||||
|
||||
const onSetCurrentView = useCallback(() => {
|
||||
const map = lastGeomapPanelInstance?.map;
|
||||
if (map) {
|
||||
const view = map.getView();
|
||||
const coords = view.getCenter();
|
||||
if (coords) {
|
||||
const center = toLonLat(coords, view.getProjection());
|
||||
onChange({
|
||||
...value,
|
||||
id: MapCenterID.Coordinates,
|
||||
lon: +center[0].toFixed(6),
|
||||
lat: +center[1].toFixed(6),
|
||||
zoom: +view.getZoom()!.toFixed(2),
|
||||
});
|
||||
}
|
||||
}
|
||||
}, [value, onChange]);
|
||||
|
||||
const onSelectView = useCallback(
|
||||
(selection: SelectableValue<string>) => {
|
||||
const v = centerPointRegistry.getIfExists(selection.value);
|
||||
if (v) {
|
||||
onChange({
|
||||
...value,
|
||||
id: v.id,
|
||||
lat: v.lat ?? value.lat,
|
||||
lon: v.lon ?? value.lon,
|
||||
zoom: v.zoom ?? value.zoom,
|
||||
});
|
||||
}
|
||||
},
|
||||
[value, onChange]
|
||||
);
|
||||
|
||||
return (
|
||||
<>
|
||||
<InlineFieldRow>
|
||||
<InlineField label="View" labelWidth={labelWidth} grow={true}>
|
||||
<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>
|
||||
</>
|
||||
)}
|
||||
|
||||
<InlineFieldRow>
|
||||
<InlineField label="Zoom" labelWidth={labelWidth} grow={true}>
|
||||
<NumberInput
|
||||
value={value.zoom ?? 1}
|
||||
min={1}
|
||||
max={18}
|
||||
step={0.01}
|
||||
onChange={(v) => {
|
||||
onChange({ ...value, zoom: v });
|
||||
}}
|
||||
/>
|
||||
</InlineField>
|
||||
</InlineFieldRow>
|
||||
|
||||
<VerticalGroup>
|
||||
<Button variant="secondary" size="sm" fullWidth onClick={onSetCurrentView}>
|
||||
<span>Use current map settings</span>
|
||||
</Button>
|
||||
</VerticalGroup>
|
||||
</>
|
||||
);
|
||||
};
|
@ -1,18 +0,0 @@
|
||||
import React, { FC } from 'react';
|
||||
import { StandardEditorProps } from '@grafana/data';
|
||||
import { GeomapPanelOptions } from '../types';
|
||||
import { NumberInput } from '../components/NumberInput';
|
||||
|
||||
export const MapZoomEditor: FC<StandardEditorProps<number | undefined, any, GeomapPanelOptions>> = ({
|
||||
value,
|
||||
onChange,
|
||||
context,
|
||||
}) => {
|
||||
// TODO:
|
||||
// Somehow use context to get the current map and listen to zoom changes
|
||||
return (
|
||||
<div>
|
||||
<NumberInput value={value} min={1} max={30} onChange={onChange} />
|
||||
</div>
|
||||
);
|
||||
};
|
@ -57,11 +57,9 @@ describe('Worldmap Migrations', () => {
|
||||
},
|
||||
"layers": Array [],
|
||||
"view": Object {
|
||||
"center": Object {
|
||||
"id": "europe",
|
||||
"lat": 46,
|
||||
"lon": 14,
|
||||
},
|
||||
"id": "europe",
|
||||
"lat": 46,
|
||||
"lon": 14,
|
||||
"zoom": 6,
|
||||
},
|
||||
},
|
||||
|
@ -27,9 +27,7 @@ export function worldmapToGeomapOptions(angular: any): { fieldConfig: FieldConfi
|
||||
|
||||
const options: GeomapPanelOptions = {
|
||||
view: {
|
||||
center: {
|
||||
id: MapCenterID.Zero,
|
||||
},
|
||||
id: MapCenterID.Zero,
|
||||
},
|
||||
controls: {
|
||||
showZoom: true,
|
||||
@ -88,11 +86,11 @@ export function worldmapToGeomapOptions(angular: any): { fieldConfig: FieldConfi
|
||||
Europe: 'europe',
|
||||
'West Asia': 'west-asia',
|
||||
'SE Asia': 'se-asia',
|
||||
'Last GeoHash': MapCenterID.LastPoint,
|
||||
'Last GeoHash': MapCenterID.Coordinates, // MapCenterID.LastPoint,
|
||||
};
|
||||
options.view.center.id = mapCenters[angular.mapCenter as any];
|
||||
options.view.center.lat = asNumber(angular.mapCenterLatitude);
|
||||
options.view.center.lon = asNumber(angular.mapCenterLongitude);
|
||||
options.view.id = mapCenters[angular.mapCenter as any];
|
||||
options.view.lat = asNumber(angular.mapCenterLatitude);
|
||||
options.view.lon = asNumber(angular.mapCenterLongitude);
|
||||
return { fieldConfig, options };
|
||||
}
|
||||
|
||||
|
@ -2,9 +2,8 @@ import { FrameGeometrySourceMode, PanelPlugin } from '@grafana/data';
|
||||
import { BaseLayerEditor } from './editor/BaseLayerEditor';
|
||||
import { DataLayersEditor } from './editor/DataLayersEditor';
|
||||
import { GeomapPanel } from './GeomapPanel';
|
||||
import { MapCenterEditor } from './editor/MapCenterEditor';
|
||||
import { MapViewEditor } from './editor/MapViewEditor';
|
||||
import { defaultView, GeomapPanelOptions } from './types';
|
||||
import { MapZoomEditor } from './editor/MapZoomEditor';
|
||||
import { mapPanelChangedHandler } from './migrations';
|
||||
import { defaultGrafanaThemedMap } from './layers/basemaps';
|
||||
import { MARKERS_LAYER_ID } from './layers/data/markersLayer';
|
||||
@ -17,20 +16,12 @@ export const plugin = new PanelPlugin<GeomapPanelOptions>(GeomapPanel)
|
||||
let category = ['Map View'];
|
||||
builder.addCustomEditor({
|
||||
category,
|
||||
id: 'view.center',
|
||||
path: 'view.center',
|
||||
name: 'Center',
|
||||
editor: MapCenterEditor,
|
||||
defaultValue: defaultView.center,
|
||||
});
|
||||
|
||||
builder.addCustomEditor({
|
||||
category,
|
||||
id: 'view.zoom',
|
||||
path: 'view.zoom',
|
||||
name: 'Initial zoom',
|
||||
editor: MapZoomEditor,
|
||||
defaultValue: defaultView.zoom,
|
||||
id: 'view',
|
||||
path: 'view',
|
||||
name: 'Initial view', // don't show it
|
||||
description: 'This location will show when the panel first loads',
|
||||
editor: MapViewEditor,
|
||||
defaultValue: defaultView,
|
||||
});
|
||||
|
||||
builder.addBooleanSwitch({
|
||||
|
@ -23,14 +23,10 @@ export interface ControlsOptions {
|
||||
showDebug?: boolean;
|
||||
}
|
||||
|
||||
export interface MapCenterConfig {
|
||||
export interface MapViewConfig {
|
||||
id: string; // placename > lookup
|
||||
lat?: number;
|
||||
lon?: number;
|
||||
}
|
||||
|
||||
export interface MapViewConfig {
|
||||
center: MapCenterConfig;
|
||||
zoom?: number;
|
||||
minZoom?: number;
|
||||
maxZoom?: number;
|
||||
@ -38,9 +34,9 @@ export interface MapViewConfig {
|
||||
}
|
||||
|
||||
export const defaultView: MapViewConfig = {
|
||||
center: {
|
||||
id: MapCenterID.Zero,
|
||||
},
|
||||
id: MapCenterID.Zero,
|
||||
lat: 0,
|
||||
lon: 0,
|
||||
zoom: 1,
|
||||
};
|
||||
|
||||
|
@ -3,12 +3,12 @@ import { Registry, RegistryItem } from '@grafana/data';
|
||||
interface MapCenterItems extends RegistryItem {
|
||||
lat?: number;
|
||||
lon?: number;
|
||||
zoom?: number;
|
||||
}
|
||||
|
||||
export enum MapCenterID {
|
||||
Zero = 'zero',
|
||||
Coordinates = 'coords',
|
||||
LastPoint = 'last',
|
||||
}
|
||||
|
||||
export const centerPointRegistry = new Registry<MapCenterItems>(() => [
|
||||
@ -23,31 +23,31 @@ export const centerPointRegistry = new Registry<MapCenterItems>(() => [
|
||||
name: 'North America',
|
||||
lat: 40,
|
||||
lon: -100,
|
||||
zoom: 4,
|
||||
},
|
||||
{
|
||||
id: 'europe',
|
||||
name: 'Europe',
|
||||
lat: 46,
|
||||
lon: 14,
|
||||
zoom: 4,
|
||||
},
|
||||
{
|
||||
id: 'west-asia',
|
||||
name: 'West Asia',
|
||||
lat: 26,
|
||||
lon: 53,
|
||||
zoom: 4,
|
||||
},
|
||||
{
|
||||
id: 'se-asia',
|
||||
name: 'South-east Asia',
|
||||
lat: 10,
|
||||
lon: 106,
|
||||
zoom: 4,
|
||||
},
|
||||
{
|
||||
id: MapCenterID.Coordinates as string,
|
||||
name: 'Coordinates',
|
||||
},
|
||||
{
|
||||
id: MapCenterID.LastPoint as string,
|
||||
name: 'Last value',
|
||||
},
|
||||
]);
|
||||
|
Loading…
Reference in New Issue
Block a user