diff --git a/public/app/plugins/panel/geomap/GeomapPanel.tsx b/public/app/plugins/panel/geomap/GeomapPanel.tsx index 5c9bc7923e9..3f45586da2f 100644 --- a/public/app/plugins/panel/geomap/GeomapPanel.tsx +++ b/public/app/plugins/panel/geomap/GeomapPanel.tsx @@ -58,7 +58,7 @@ export class GeomapPanel extends Component { this.map.updateSize(); } - // External configuraiton changed + // External configuration changed let layersChanged = false; if (this.props.options !== nextProps.options) { layersChanged = this.optionsChanged(nextProps.options); @@ -86,7 +86,7 @@ export class GeomapPanel extends Component { } if (options.controls !== oldOptions.controls) { - console.log('Crontrols changed'); + console.log('Controls changed'); this.initControls(options.controls ?? { showZoom: true, showAttribution: true }); } diff --git a/public/app/plugins/panel/geomap/dims/color.ts b/public/app/plugins/panel/geomap/dims/color.ts index 8ec6a0feb1e..bdcb67f3039 100644 --- a/public/app/plugins/panel/geomap/dims/color.ts +++ b/public/app/plugins/panel/geomap/dims/color.ts @@ -13,7 +13,7 @@ export function getColorDimension( ): DimensionSupplier { const field = findField(frame, config.field); if (!field) { - const v = config.fixed ?? 'grey'; + const v = theme.visualization.getColorByName(config.fixed) ?? 'grey'; return { isAssumed: Boolean(config.field?.length) || !config.fixed, fixed: v, diff --git a/public/app/plugins/panel/geomap/dims/editors/ColorDimensionEditor.tsx b/public/app/plugins/panel/geomap/dims/editors/ColorDimensionEditor.tsx index 0ea9fc5fa43..70fb94d4758 100644 --- a/public/app/plugins/panel/geomap/dims/editors/ColorDimensionEditor.tsx +++ b/public/app/plugins/panel/geomap/dims/editors/ColorDimensionEditor.tsx @@ -64,7 +64,7 @@ export const ColorDimensionEditor: FC {isFixed && (
- +
)} diff --git a/public/app/plugins/panel/geomap/layers/basemaps/esri.ts b/public/app/plugins/panel/geomap/layers/basemaps/esri.ts index cee39c0ad08..e3eca09ac1a 100644 --- a/public/app/plugins/panel/geomap/layers/basemaps/esri.ts +++ b/public/app/plugins/panel/geomap/layers/basemaps/esri.ts @@ -49,7 +49,9 @@ export const publicServiceRegistry = new Registry(() => [ ]); export interface ESRIXYZConfig extends XYZConfig { - server: string; + config: { + server: string; + }; } export const esriXYZTiles: MapLayerRegistryItem = { @@ -60,7 +62,7 @@ export const esriXYZTiles: MapLayerRegistryItem = { create: (map: Map, options: MapLayerOptions, theme: GrafanaTheme2) => ({ init: () => { const cfg = { ...options.config }; - const svc = publicServiceRegistry.getIfExists(cfg.server ?? DEFAULT_SERVICE)!; + const svc = publicServiceRegistry.getIfExists(cfg.config?.server ?? DEFAULT_SERVICE)!; if (svc.id !== CUSTOM_SERVICE) { const base = 'https://services.arcgisonline.com/ArcGIS/rest/services/'; cfg.url = `${base}${svc.slug}/MapServer/tile/{z}/{y}/{x}`; @@ -87,7 +89,7 @@ export const esriXYZTiles: MapLayerRegistryItem = { settings: { placeholder: defaultXYZConfig.url, }, - showIf: (cfg) => cfg.server === CUSTOM_SERVICE, + showIf: (cfg) => cfg.config?.server === CUSTOM_SERVICE, }) .addTextInput({ path: 'config.attribution', @@ -95,7 +97,7 @@ export const esriXYZTiles: MapLayerRegistryItem = { settings: { placeholder: defaultXYZConfig.attribution, }, - showIf: (cfg) => cfg.server === CUSTOM_SERVICE, + showIf: (cfg) => cfg.config?.server === CUSTOM_SERVICE, }); }, diff --git a/public/app/plugins/panel/geomap/layers/data/markersLayer.tsx b/public/app/plugins/panel/geomap/layers/data/markersLayer.tsx index 48ed396d413..bf21fa56e75 100644 --- a/public/app/plugins/panel/geomap/layers/data/markersLayer.tsx +++ b/public/app/plugins/panel/geomap/layers/data/markersLayer.tsx @@ -3,7 +3,7 @@ import Map from 'ol/Map'; import Feature from 'ol/Feature'; import * as layer from 'ol/layer'; import * as source from 'ol/source'; -import * as style from 'ol/style'; + import tinycolor from 'tinycolor2'; import { dataFrameToPoints, getLocationMatchers } from '../../utils/location'; import { ColorDimensionConfig, ScaleDimensionConfig, } from '../../dims/types'; @@ -11,13 +11,14 @@ import { getScaledDimension, } from '../../dims/scale'; import { getColorDimension, } from '../../dims/color'; import { ScaleDimensionEditor } from '../../dims/editors/ScaleDimensionEditor'; import { ColorDimensionEditor } from '../../dims/editors/ColorDimensionEditor'; - +import { markerMakers } from '../../utils/regularShapes'; // Configuration options for Circle overlays export interface MarkersConfig { size: ScaleDimensionConfig; color: ColorDimensionConfig; fillOpacity: number; + shape?: string; } const defaultOptions: MarkersConfig = { @@ -27,9 +28,10 @@ const defaultOptions: MarkersConfig = { max: 15, }, color: { - fixed: '#f00', + fixed: 'dark-green', // picked from theme }, fillOpacity: 0.4, + shape: 'circle', }; export const MARKERS_LAYER_ID = "markers"; @@ -65,6 +67,11 @@ export const markersLayer: MapLayerRegistryItem = { ...defaultOptions, ...options?.config, }; + + let shape = markerMakers.getIfExists(config.shape); + if (!shape) { + shape = markerMakers.get('circle'); + } return { init: () => vectorLayer, @@ -99,20 +106,7 @@ export const markersLayer: MapLayerRegistryItem = { geometry: info.points[i], }); - // Set the style of each feature dot - dot.setStyle(new style.Style({ - image: new style.Circle({ - // Stroke determines the outline color of the circle - stroke: new style.Stroke({ - color: color, - }), - // Fill determines the color to fill the whole circle - fill: new style.Fill({ - color: tinycolor(fillColor).toString(), - }), - radius: radius, - }) - })); + dot.setStyle(shape!.make(color, fillColor, radius)); features.push(dot); }; @@ -150,16 +144,25 @@ export const markersLayer: MapLayerRegistryItem = { max: 20, }, }) + .addSelect({ + path: 'config.shape', + name: 'Marker Shape', + settings: { + options: markerMakers.selectOptions().options, + }, + defaultValue: 'circle', + }) .addSliderInput({ - path: 'config.fillOpacity', - name: 'Fill opacity', - defaultValue: defaultOptions.fillOpacity, - settings: { - min: 0, - max: 1, - step: 0.1, - }, - }); + path: 'config.fillOpacity', + name: 'Fill opacity', + defaultValue: defaultOptions.fillOpacity, + settings: { + min: 0, + max: 1, + step: 0.1, + }, + showIf: (cfg) => (markerMakers.getIfExists((cfg as any).config?.shape)?.hasFill), + }); }, // fill in the default values diff --git a/public/app/plugins/panel/geomap/utils/regularShapes.ts b/public/app/plugins/panel/geomap/utils/regularShapes.ts new file mode 100644 index 00000000000..b493e49297e --- /dev/null +++ b/public/app/plugins/panel/geomap/utils/regularShapes.ts @@ -0,0 +1,108 @@ +import { Fill, RegularShape, Stroke, Style, Circle } from 'ol/style'; +import { Registry, RegistryItem } from '@grafana/data'; + +interface MarkerMaker extends RegistryItem { + make: (color: string, fillColor: string, radius: number) => Style; + hasFill: boolean; +} + +export const markerMakers = new Registry(() => [ + { + id: 'circle', + name: 'Circle', + hasFill: true, + make: (color: string, fillColor: string, radius: number) => { + return new Style({ + image: new Circle({ + stroke: new Stroke({ color: color }), + fill: new Fill({ color: fillColor }), + radius: radius, + }), + }); + }, + }, + { + id: 'square', + name: 'Square', + hasFill: true, + make: (color: string, fillColor: string, radius: number) => { + return new Style({ + image: new RegularShape({ + fill: new Fill({ color: fillColor }), + stroke: new Stroke({ color: color, width: 1 }), + points: 4, + radius: radius, + angle: Math.PI / 4, + }), + }); + }, + }, + { + id: 'triangle', + name: 'Triangle', + hasFill: true, + make: (color: string, fillColor: string, radius: number) => { + return new Style({ + image: new RegularShape({ + fill: new Fill({ color: fillColor }), + stroke: new Stroke({ color: color, width: 1 }), + points: 3, + radius: radius, + rotation: Math.PI / 4, + angle: 0, + }), + }); + }, + }, + { + id: 'star', + name: 'Star', + hasFill: true, + make: (color: string, fillColor: string, radius: number) => { + return new Style({ + image: new RegularShape({ + fill: new Fill({ color: fillColor }), + stroke: new Stroke({ color: color, width: 1 }), + points: 5, + radius: radius, + radius2: radius * 0.4, + angle: 0, + }), + }); + }, + }, + { + id: 'cross', + name: 'Cross', + hasFill: false, + make: (color: string, fillColor: string, radius: number) => { + return new Style({ + image: new RegularShape({ + fill: new Fill({ color: fillColor }), + stroke: new Stroke({ color: color, width: 1 }), + points: 4, + radius: radius, + radius2: 0, + angle: 0, + }), + }); + }, + }, + { + id: 'x', + name: 'X', + hasFill: false, + make: (color: string, fillColor: string, radius: number) => { + return new Style({ + image: new RegularShape({ + fill: new Fill({ color: fillColor }), + stroke: new Stroke({ color: color, width: 1 }), + points: 4, + radius: radius, + radius2: 0, + angle: Math.PI / 4, + }), + }); + }, + }, +]);