1import { FieldConfigSource, PanelModel, PanelTypeChangedHandler, Threshold, ThresholdsMode } from '@grafana/data'; 2import { ResourceDimensionMode } from 'app/features/dimensions'; 3import { cloneDeep } from 'lodash'; 4import { MarkersConfig } from './layers/data/markersLayer'; 5import { getMarkerAsPath } from './style/markers'; 6import { defaultStyleConfig } from './style/types'; 7import { GeomapPanelOptions } from './types'; 8import { MapCenterID } from './view'; 9 10/** 11 * This is called when the panel changes from another panel 12 */ 13export const mapPanelChangedHandler: PanelTypeChangedHandler = (panel, prevPluginId, prevOptions, prevFieldConfig) => { 14 // Changing from angular/worldmap panel to react/openlayers 15 if (prevPluginId === 'grafana-worldmap-panel' && prevOptions.angular) { 16 const { fieldConfig, options } = worldmapToGeomapOptions({ 17 ...prevOptions.angular, 18 fieldConfig: prevFieldConfig, 19 }); 20 panel.fieldConfig = fieldConfig; // Mutates the incoming panel 21 return options; 22 } 23 24 return {}; 25}; 26 27export function worldmapToGeomapOptions(angular: any): { fieldConfig: FieldConfigSource; options: GeomapPanelOptions } { 28 const fieldConfig: FieldConfigSource = { 29 defaults: {}, 30 overrides: [], 31 }; 32 33 const options: GeomapPanelOptions = { 34 view: { 35 id: MapCenterID.Zero, 36 }, 37 controls: { 38 showZoom: true, 39 mouseWheelZoom: Boolean(angular.mouseWheelZoom), 40 }, 41 basemap: { 42 type: 'default', // was carto 43 name: 'Basemap', 44 }, 45 layers: [ 46 // TODO? depends on current configs 47 ], 48 }; 49 50 let v = asNumber(angular.decimals); 51 if (v) { 52 fieldConfig.defaults.decimals = v; 53 } 54 55 // Convert thresholds and color values 56 if (angular.thresholds && angular.colors) { 57 const levels = angular.thresholds.split(',').map((strVale: string) => { 58 return Number(strVale.trim()); 59 }); 60 61 // One more color than threshold 62 const thresholds: Threshold[] = []; 63 for (const color of angular.colors) { 64 const idx = thresholds.length - 1; 65 if (idx >= 0) { 66 thresholds.push({ value: levels[idx], color }); 67 } else { 68 thresholds.push({ value: -Infinity, color }); 69 } 70 } 71 72 fieldConfig.defaults.thresholds = { 73 mode: ThresholdsMode.Absolute, 74 steps: thresholds, 75 }; 76 } 77 78 v = asNumber(angular.initialZoom); 79 if (v) { 80 options.view.zoom = v; 81 } 82 83 // mapCenter: 'Europe', 84 // mapCenterLatitude: 46, 85 // mapCenterLongitude: 14, 86 // 87 // Map center (from worldmap) 88 const mapCenters: any = { 89 '(0°, 0°)': MapCenterID.Zero, 90 'North America': 'north-america', 91 Europe: 'europe', 92 'West Asia': 'west-asia', 93 'SE Asia': 'se-asia', 94 'Last GeoHash': MapCenterID.Coordinates, // MapCenterID.LastPoint, 95 }; 96 options.view.id = mapCenters[angular.mapCenter as any]; 97 options.view.lat = asNumber(angular.mapCenterLatitude); 98 options.view.lon = asNumber(angular.mapCenterLongitude); 99 return { fieldConfig, options }; 100} 101 102function asNumber(v: any): number | undefined { 103 const num = +v; 104 return isNaN(num) ? undefined : num; 105} 106 107export const mapMigrationHandler = (panel: PanelModel): Partial<GeomapPanelOptions> => { 108 const pluginVersion = panel?.pluginVersion ?? ''; 109 110 // before 8.3, only one layer was supported! 111 if (pluginVersion.startsWith('8.1') || pluginVersion.startsWith('8.2')) { 112 const layers = panel.options?.layers; 113 if (layers?.length === 1) { 114 const layer = panel.options.layers[0]; 115 if (layer?.type === 'markers' && layer.config) { 116 // Moving style to child object 117 const oldConfig = layer.config; 118 const config: MarkersConfig = { 119 style: cloneDeep(defaultStyleConfig), 120 showLegend: Boolean(oldConfig.showLegend), 121 }; 122 123 if (oldConfig.size) { 124 config.style.size = oldConfig.size; 125 } 126 if (oldConfig.color) { 127 config.style.color = oldConfig.color; 128 } 129 if (oldConfig.fillOpacity) { 130 config.style.opacity = oldConfig.fillOpacity; 131 } 132 const symbol = getMarkerAsPath(oldConfig.shape); 133 if (symbol) { 134 config.style.symbol = { 135 fixed: symbol, 136 mode: ResourceDimensionMode.Fixed, 137 }; 138 } 139 return { ...panel.options, layers: [{ ...layer, config }] }; 140 } 141 } 142 } 143 return panel.options; 144}; 145