diff --git a/docs/sources/visualizations/panels-visualizations/visualizations/geomap/index.md b/docs/sources/visualizations/panels-visualizations/visualizations/geomap/index.md index 209df209a77..12137f728b3 100644 --- a/docs/sources/visualizations/panels-visualizations/visualizations/geomap/index.md +++ b/docs/sources/visualizations/panels-visualizations/visualizations/geomap/index.md @@ -177,6 +177,16 @@ Default Views are also available including: | South Asia | South-East Asia | East Asia | Australia | Oceania | +#### Enable dashboard variable (Experimental) + +If toggled the Geomap panel update, if exists, the dashboard's variable named `mapViewData` with the bounding box of the current view. + +The variable can be a `Custom` variable type and can be hidden on the dashbaord (Show on dashboard: Nothing). + +You can use then the variable inside your query to receive on the server side a string like this: + + 4.102646520428928,44.489253792751214,12.793524298588558,46.4346026776777 + #### Share view The **Share view** option allows you to link the movement and zoom actions of multiple map visualizations within the same dashboard. The map visualizations that have this option enabled act in tandem when one of them is moved or zoomed, leaving the other ones independent. diff --git a/packages/grafana-schema/src/raw/composable/geomap/panelcfg/x/GeomapPanelCfg_types.gen.ts b/packages/grafana-schema/src/raw/composable/geomap/panelcfg/x/GeomapPanelCfg_types.gen.ts index 74bdafa169d..95a1911ab70 100644 --- a/packages/grafana-schema/src/raw/composable/geomap/panelcfg/x/GeomapPanelCfg_types.gen.ts +++ b/packages/grafana-schema/src/raw/composable/geomap/panelcfg/x/GeomapPanelCfg_types.gen.ts @@ -26,6 +26,7 @@ export const defaultOptions: Partial = { export interface MapViewConfig { allLayers?: boolean; + dashboardVariable?: boolean; id: string; lastOnly?: boolean; lat?: number; diff --git a/public/app/plugins/panel/geomap/GeomapPanel.tsx b/public/app/plugins/panel/geomap/GeomapPanel.tsx index cb532f0ed95..17b5a498a4c 100644 --- a/public/app/plugins/panel/geomap/GeomapPanel.tsx +++ b/public/app/plugins/panel/geomap/GeomapPanel.tsx @@ -7,6 +7,7 @@ import Attribution from 'ol/control/Attribution'; import ScaleLine from 'ol/control/ScaleLine'; import Zoom from 'ol/control/Zoom'; import { Coordinate } from 'ol/coordinate'; +import { EventsKey } from 'ol/events'; import { isEmpty } from 'ol/extent'; import MouseWheelZoom from 'ol/interaction/MouseWheelZoom'; import { fromLonLat, transformExtent } from 'ol/proj'; @@ -16,7 +17,7 @@ import { Subscription } from 'rxjs'; import { DataHoverEvent, PanelData, PanelProps } from '@grafana/data'; import { t } from '@grafana/i18n'; -import { config } from '@grafana/runtime'; +import { config, locationService } from '@grafana/runtime'; import { PanelContext, PanelContextRoot } from '@grafana/ui'; import { appEvents } from 'app/core/app_events'; import { VariablesChanged } from 'app/features/variables/types'; @@ -73,6 +74,8 @@ export class GeomapPanel extends Component { layers: MapLayerState[] = []; readonly byName = new Map(); + mapViewData?: string; + constructor(props: Props) { super(props); this.state = { ttipOpen: false, legends: [] }; @@ -125,6 +128,9 @@ export class GeomapPanel extends Component { // Check for resize if (this.props.height !== nextProps.height || this.props.width !== nextProps.width) { this.map.updateSize(); + if (this.props.options?.view?.dashboardVariable) { + this.updateGeoVariables(this.map.getView()); + } } // External data changed @@ -331,7 +337,37 @@ export class GeomapPanel extends Component { return view; }; + /** + * Updates the dashboard variable `mapViewData` with the view extent value. + * Use a debounce strategy to wait the user stop dragging or zooming the map. + */ + private timeoutId: NodeJS.Timeout | null = null; // for debounce + + updateGeoVariables = (view: View) => { + const bounds = view.calculateExtent(); + const bounds4326 = transformExtent(bounds, 'EPSG:3857', 'EPSG:4326'); + console.log('GeomapPanel.updateGeoVariables', bounds4326); + if (this.timeoutId) { + clearTimeout(this.timeoutId); + } + this.timeoutId = setTimeout(() => { + locationService.partial({ 'var-mapViewData': `${bounds4326}` }, true); + }, 500); + }; + + private viewListernerKey: EventsKey | null = null; + initViewExtent(view: View, config: MapViewConfig) { + if (config.dashboardVariable) { + if (this.viewListernerKey != null) { + view.un('change', this.viewListernerKey.listener); + } + this.viewListernerKey = view.on('change', () => { + this.updateGeoVariables(view); + }); + this.updateGeoVariables(view); + } + const v = centerPointRegistry.getIfExists(config.id); if (v) { let coord: Coordinate | undefined = undefined; diff --git a/public/app/plugins/panel/geomap/module.tsx b/public/app/plugins/panel/geomap/module.tsx index a88a3bfbe02..3a2fadb7353 100644 --- a/public/app/plugins/panel/geomap/module.tsx +++ b/public/app/plugins/panel/geomap/module.tsx @@ -32,6 +32,14 @@ export const plugin = new PanelPlugin(GeomapPanel) defaultValue: defaultMapViewConfig, }); + builder.addBooleanSwitch({ + category, + path: 'view.dashboardVariable', + description: 'Store view bounds into the "mapViewData" dashboard variable.', + name: 'Enable dashboard variable (Experimental)', + defaultValue: false, + }); + builder.addBooleanSwitch({ category, path: 'view.shared', diff --git a/public/app/plugins/panel/geomap/panelcfg.cue b/public/app/plugins/panel/geomap/panelcfg.cue index 7384ec581e5..17360b0fa56 100644 --- a/public/app/plugins/panel/geomap/panelcfg.cue +++ b/public/app/plugins/panel/geomap/panelcfg.cue @@ -46,6 +46,7 @@ composableKinds: PanelCfg: { layer?: string shared?: bool noRepeat?: bool | *false + dashboardVariable?: bool } @cuetsy(kind="interface") ControlsOptions: { diff --git a/public/app/plugins/panel/geomap/panelcfg.gen.ts b/public/app/plugins/panel/geomap/panelcfg.gen.ts index cffd8e01e13..cf83f827e67 100644 --- a/public/app/plugins/panel/geomap/panelcfg.gen.ts +++ b/public/app/plugins/panel/geomap/panelcfg.gen.ts @@ -24,6 +24,7 @@ export const defaultOptions: Partial = { export interface MapViewConfig { allLayers?: boolean; + dashboardVariable?: boolean; id: string; lastOnly?: boolean; lat?: number;