mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
Geomap: support multiple layers (#40906)
This commit is contained in:
@@ -50,29 +50,29 @@ export const carto: MapLayerRegistryItem<CartoConfig> = {
|
||||
}),
|
||||
});
|
||||
},
|
||||
}),
|
||||
|
||||
registerOptionsUI: (builder) => {
|
||||
builder
|
||||
.addRadio({
|
||||
path: 'config.theme',
|
||||
name: 'Theme',
|
||||
settings: {
|
||||
options: [
|
||||
{ value: LayerTheme.Auto, label: 'Auto', description: 'Match grafana theme' },
|
||||
{ value: LayerTheme.Light, label: 'Light' },
|
||||
{ value: LayerTheme.Dark, label: 'Dark' },
|
||||
],
|
||||
},
|
||||
defaultValue: defaultCartoConfig.theme!,
|
||||
})
|
||||
.addBooleanSwitch({
|
||||
path: 'config.showLabels',
|
||||
name: 'Show labels',
|
||||
description: '',
|
||||
defaultValue: defaultCartoConfig.showLabels,
|
||||
});
|
||||
},
|
||||
registerOptionsUI: (builder) => {
|
||||
builder
|
||||
.addRadio({
|
||||
path: 'config.theme',
|
||||
name: 'Theme',
|
||||
settings: {
|
||||
options: [
|
||||
{ value: LayerTheme.Auto, label: 'Auto', description: 'Match grafana theme' },
|
||||
{ value: LayerTheme.Light, label: 'Light' },
|
||||
{ value: LayerTheme.Dark, label: 'Dark' },
|
||||
],
|
||||
},
|
||||
defaultValue: defaultCartoConfig.theme!,
|
||||
})
|
||||
.addBooleanSwitch({
|
||||
path: 'config.showLabels',
|
||||
name: 'Show labels',
|
||||
description: '',
|
||||
defaultValue: defaultCartoConfig.showLabels,
|
||||
});
|
||||
},
|
||||
}),
|
||||
};
|
||||
|
||||
export const cartoLayers = [carto];
|
||||
|
||||
@@ -66,35 +66,36 @@ export const esriXYZTiles: MapLayerRegistryItem<ESRIXYZConfig> = {
|
||||
cfg.attribution = `Tiles © <a href="${base}${svc.slug}/MapServer">ArcGIS</a>`;
|
||||
}
|
||||
const opts = { ...options, config: cfg as XYZConfig };
|
||||
return xyzTiles.create(map, opts, theme);
|
||||
},
|
||||
|
||||
registerOptionsUI: (builder) => {
|
||||
builder
|
||||
.addSelect({
|
||||
path: 'config.server',
|
||||
name: 'Server instance',
|
||||
settings: {
|
||||
options: publicServiceRegistry.selectOptions().options,
|
||||
},
|
||||
})
|
||||
.addTextInput({
|
||||
path: 'config.url',
|
||||
name: 'URL template',
|
||||
description: 'Must include {x}, {y} or {-y}, and {z} placeholders',
|
||||
settings: {
|
||||
placeholder: defaultXYZConfig.url,
|
||||
},
|
||||
showIf: (cfg) => cfg.config?.server === CUSTOM_SERVICE,
|
||||
})
|
||||
.addTextInput({
|
||||
path: 'config.attribution',
|
||||
name: 'Attribution',
|
||||
settings: {
|
||||
placeholder: defaultXYZConfig.attribution,
|
||||
},
|
||||
showIf: (cfg) => cfg.config?.server === CUSTOM_SERVICE,
|
||||
});
|
||||
return xyzTiles.create(map, opts, theme).then((xyz) => {
|
||||
xyz.registerOptionsUI = (builder) => {
|
||||
builder
|
||||
.addSelect({
|
||||
path: 'config.server',
|
||||
name: 'Server instance',
|
||||
settings: {
|
||||
options: publicServiceRegistry.selectOptions().options,
|
||||
},
|
||||
})
|
||||
.addTextInput({
|
||||
path: 'config.url',
|
||||
name: 'URL template',
|
||||
description: 'Must include {x}, {y} or {-y}, and {z} placeholders',
|
||||
settings: {
|
||||
placeholder: defaultXYZConfig.url,
|
||||
},
|
||||
showIf: (cfg) => cfg.config?.server === CUSTOM_SERVICE,
|
||||
})
|
||||
.addTextInput({
|
||||
path: 'config.attribution',
|
||||
name: 'Attribution',
|
||||
settings: {
|
||||
placeholder: defaultXYZConfig.attribution,
|
||||
},
|
||||
showIf: (cfg) => cfg.config?.server === CUSTOM_SERVICE,
|
||||
});
|
||||
};
|
||||
return xyz;
|
||||
});
|
||||
},
|
||||
|
||||
defaultOptions: {
|
||||
|
||||
@@ -37,26 +37,25 @@ export const xyzTiles: MapLayerRegistryItem<XYZConfig> = {
|
||||
maxZoom: cfg.maxZoom,
|
||||
});
|
||||
},
|
||||
registerOptionsUI: (builder) => {
|
||||
builder
|
||||
.addTextInput({
|
||||
path: 'config.url',
|
||||
name: 'URL template',
|
||||
description: 'Must include {x}, {y} or {-y}, and {z} placeholders',
|
||||
settings: {
|
||||
placeholder: defaultXYZConfig.url,
|
||||
},
|
||||
})
|
||||
.addTextInput({
|
||||
path: 'config.attribution',
|
||||
name: 'Attribution',
|
||||
settings: {
|
||||
placeholder: defaultXYZConfig.attribution,
|
||||
},
|
||||
});
|
||||
},
|
||||
}),
|
||||
|
||||
registerOptionsUI: (builder) => {
|
||||
builder
|
||||
.addTextInput({
|
||||
path: 'config.url',
|
||||
name: 'URL template',
|
||||
description: 'Must include {x}, {y} or {-y}, and {z} placeholders',
|
||||
settings: {
|
||||
placeholder: defaultXYZConfig.url,
|
||||
},
|
||||
})
|
||||
.addTextInput({
|
||||
path: 'config.attribution',
|
||||
name: 'Attribution',
|
||||
settings: {
|
||||
placeholder: defaultXYZConfig.attribution,
|
||||
},
|
||||
});
|
||||
},
|
||||
};
|
||||
|
||||
export const genericLayers = [xyzTiles];
|
||||
|
||||
@@ -3,6 +3,7 @@ import Map from 'ol/Map';
|
||||
import VectorLayer from 'ol/layer/Vector';
|
||||
import VectorSource from 'ol/source/Vector';
|
||||
import GeoJSON from 'ol/format/GeoJSON';
|
||||
import { unByKey } from 'ol/Observable';
|
||||
import { Feature } from 'ol';
|
||||
import { Geometry } from 'ol/geom';
|
||||
import { getGeoMapStyle } from '../../utils/getGeoMapStyle';
|
||||
@@ -53,6 +54,19 @@ export const geojsonMapper: MapLayerRegistryItem<GeoJSONMapperConfig> = {
|
||||
format: new GeoJSON(),
|
||||
});
|
||||
|
||||
const key = source.on('change', () => {
|
||||
if (source.getState() == 'ready') {
|
||||
unByKey(key);
|
||||
// var olFeatures = source.getFeatures(); // olFeatures.length === 1
|
||||
// window.setTimeout(function () {
|
||||
// var olFeatures = source.getFeatures(); // olFeatures.length > 1
|
||||
// // Only after using setTimeout can I search the feature list... :(
|
||||
// }, 100)
|
||||
|
||||
console.log('SOURCE READY!!!', source.getFeatures().length);
|
||||
}
|
||||
});
|
||||
|
||||
const defaultStyle = new Style({
|
||||
stroke: new Stroke({
|
||||
color: DEFAULT_STYLE_RULE.fillColor,
|
||||
@@ -80,37 +94,40 @@ export const geojsonMapper: MapLayerRegistryItem<GeoJSONMapperConfig> = {
|
||||
update: (data: PanelData) => {
|
||||
console.log('todo... find values matching the ID and update');
|
||||
|
||||
// Update each feature
|
||||
source.getFeatures().forEach((f) => {
|
||||
console.log('Find: ', f.getId(), f.getProperties());
|
||||
});
|
||||
// // Update each feature
|
||||
// source.getFeatures().forEach((f) => {
|
||||
// console.log('Find: ', f.getId(), f.getProperties());
|
||||
// });
|
||||
},
|
||||
|
||||
// Geojson source url
|
||||
registerOptionsUI: (builder) => {
|
||||
const features = source.getFeatures();
|
||||
console.log('FEATURES', source.getState(), features.length, options);
|
||||
|
||||
builder
|
||||
.addSelect({
|
||||
path: 'config.src',
|
||||
name: 'GeoJSON URL',
|
||||
settings: {
|
||||
options: [
|
||||
{ label: 'public/maps/countries.geojson', value: 'public/maps/countries.geojson' },
|
||||
{ label: 'public/maps/usa-states.geojson', value: 'public/maps/usa-states.geojson' },
|
||||
],
|
||||
allowCustomValue: true,
|
||||
},
|
||||
defaultValue: defaultOptions.src,
|
||||
})
|
||||
.addCustomEditor({
|
||||
id: 'config.styles',
|
||||
path: 'config.styles',
|
||||
name: 'Style Rules',
|
||||
editor: GeomapStyleRulesEditor,
|
||||
settings: {},
|
||||
defaultValue: [],
|
||||
});
|
||||
},
|
||||
};
|
||||
},
|
||||
|
||||
// Geojson source url
|
||||
registerOptionsUI: (builder) => {
|
||||
builder
|
||||
.addSelect({
|
||||
path: 'config.src',
|
||||
name: 'GeoJSON URL',
|
||||
settings: {
|
||||
options: [
|
||||
{ label: 'public/maps/countries.geojson', value: 'public/maps/countries.geojson' },
|
||||
{ label: 'public/maps/usa-states.geojson', value: 'public/maps/usa-states.geojson' },
|
||||
],
|
||||
allowCustomValue: true,
|
||||
},
|
||||
defaultValue: defaultOptions.src,
|
||||
})
|
||||
.addCustomEditor({
|
||||
id: 'config.styles',
|
||||
path: 'config.styles',
|
||||
name: 'Style Rules',
|
||||
editor: GeomapStyleRulesEditor,
|
||||
settings: {},
|
||||
defaultValue: [],
|
||||
});
|
||||
},
|
||||
defaultOptions,
|
||||
};
|
||||
|
||||
@@ -110,52 +110,53 @@ export const heatmapLayer: MapLayerRegistryItem<HeatmapConfig> = {
|
||||
}
|
||||
vectorLayer.setGradient(colors);
|
||||
},
|
||||
|
||||
// Heatmap overlay options
|
||||
registerOptionsUI: (builder) => {
|
||||
builder
|
||||
.addCustomEditor({
|
||||
id: 'config.weight',
|
||||
path: 'config.weight',
|
||||
name: 'Weight values',
|
||||
description: 'Scale the distribution for each row',
|
||||
editor: ScaleDimensionEditor,
|
||||
settings: {
|
||||
min: 0, // no contribution
|
||||
max: 1,
|
||||
hideRange: true, // Don't show the scale factor
|
||||
},
|
||||
defaultValue: {
|
||||
// Configured values
|
||||
fixed: 1,
|
||||
min: 0,
|
||||
max: 1,
|
||||
},
|
||||
})
|
||||
.addSliderInput({
|
||||
path: 'config.radius',
|
||||
description: 'configures the size of clusters',
|
||||
name: 'Radius',
|
||||
defaultValue: defaultOptions.radius,
|
||||
settings: {
|
||||
min: 1,
|
||||
max: 50,
|
||||
step: 1,
|
||||
},
|
||||
})
|
||||
.addSliderInput({
|
||||
path: 'config.blur',
|
||||
description: 'configures the amount of blur of clusters',
|
||||
name: 'Blur',
|
||||
defaultValue: defaultOptions.blur,
|
||||
settings: {
|
||||
min: 1,
|
||||
max: 50,
|
||||
step: 1,
|
||||
},
|
||||
});
|
||||
},
|
||||
};
|
||||
},
|
||||
// Heatmap overlay options
|
||||
registerOptionsUI: (builder) => {
|
||||
builder
|
||||
.addCustomEditor({
|
||||
id: 'config.weight',
|
||||
path: 'config.weight',
|
||||
name: 'Weight values',
|
||||
description: 'Scale the distribution for each row',
|
||||
editor: ScaleDimensionEditor,
|
||||
settings: {
|
||||
min: 0, // no contribution
|
||||
max: 1,
|
||||
hideRange: true, // Don't show the scale factor
|
||||
},
|
||||
defaultValue: {
|
||||
// Configured values
|
||||
fixed: 1,
|
||||
min: 0,
|
||||
max: 1,
|
||||
},
|
||||
})
|
||||
.addSliderInput({
|
||||
path: 'config.radius',
|
||||
description: 'configures the size of clusters',
|
||||
name: 'Radius',
|
||||
defaultValue: defaultOptions.radius,
|
||||
settings: {
|
||||
min: 1,
|
||||
max: 50,
|
||||
step: 1,
|
||||
},
|
||||
})
|
||||
.addSliderInput({
|
||||
path: 'config.blur',
|
||||
description: 'configures the amount of blur of clusters',
|
||||
name: 'Blur',
|
||||
defaultValue: defaultOptions.blur,
|
||||
settings: {
|
||||
min: 1,
|
||||
max: 50,
|
||||
step: 1,
|
||||
},
|
||||
});
|
||||
},
|
||||
// fill in the default values
|
||||
defaultOptions,
|
||||
};
|
||||
|
||||
@@ -165,67 +165,68 @@ export const markersLayer: MapLayerRegistryItem<MarkersConfig> = {
|
||||
const vectorSource = new source.Vector({ features });
|
||||
vectorLayer.setSource(vectorSource);
|
||||
},
|
||||
|
||||
// Marker overlay options
|
||||
registerOptionsUI: (builder) => {
|
||||
builder
|
||||
.addCustomEditor({
|
||||
id: 'config.size',
|
||||
path: 'config.size',
|
||||
name: 'Marker Size',
|
||||
editor: ScaleDimensionEditor,
|
||||
settings: {
|
||||
min: 1,
|
||||
max: 100, // possible in the UI
|
||||
},
|
||||
defaultValue: {
|
||||
// Configured values
|
||||
fixed: DEFAULT_SIZE,
|
||||
min: 1,
|
||||
max: 20,
|
||||
},
|
||||
})
|
||||
.addCustomEditor({
|
||||
id: 'config.markerSymbol',
|
||||
path: 'config.markerSymbol',
|
||||
name: 'Marker Symbol',
|
||||
editor: ResourceDimensionEditor,
|
||||
defaultValue: defaultOptions.markerSymbol,
|
||||
settings: {
|
||||
resourceType: 'icon',
|
||||
showSourceRadio: false,
|
||||
folderName: ResourceFolderName.Marker,
|
||||
},
|
||||
})
|
||||
.addCustomEditor({
|
||||
id: 'config.color',
|
||||
path: 'config.color',
|
||||
name: 'Marker Color',
|
||||
editor: ColorDimensionEditor,
|
||||
settings: {},
|
||||
defaultValue: {
|
||||
// Configured values
|
||||
fixed: 'grey',
|
||||
},
|
||||
})
|
||||
.addSliderInput({
|
||||
path: 'config.fillOpacity',
|
||||
name: 'Fill opacity',
|
||||
defaultValue: defaultOptions.fillOpacity,
|
||||
settings: {
|
||||
min: 0,
|
||||
max: 1,
|
||||
step: 0.1,
|
||||
},
|
||||
})
|
||||
.addBooleanSwitch({
|
||||
path: 'config.showLegend',
|
||||
name: 'Show legend',
|
||||
description: 'Show legend',
|
||||
defaultValue: defaultOptions.showLegend,
|
||||
});
|
||||
},
|
||||
};
|
||||
},
|
||||
// Marker overlay options
|
||||
registerOptionsUI: (builder) => {
|
||||
builder
|
||||
.addCustomEditor({
|
||||
id: 'config.size',
|
||||
path: 'config.size',
|
||||
name: 'Marker Size',
|
||||
editor: ScaleDimensionEditor,
|
||||
settings: {
|
||||
min: 1,
|
||||
max: 100, // possible in the UI
|
||||
},
|
||||
defaultValue: {
|
||||
// Configured values
|
||||
fixed: DEFAULT_SIZE,
|
||||
min: 1,
|
||||
max: 20,
|
||||
},
|
||||
})
|
||||
.addCustomEditor({
|
||||
id: 'config.markerSymbol',
|
||||
path: 'config.markerSymbol',
|
||||
name: 'Marker Symbol',
|
||||
editor: ResourceDimensionEditor,
|
||||
defaultValue: defaultOptions.markerSymbol,
|
||||
settings: {
|
||||
resourceType: 'icon',
|
||||
showSourceRadio: false,
|
||||
folderName: ResourceFolderName.Marker,
|
||||
},
|
||||
})
|
||||
.addCustomEditor({
|
||||
id: 'config.color',
|
||||
path: 'config.color',
|
||||
name: 'Marker Color',
|
||||
editor: ColorDimensionEditor,
|
||||
settings: {},
|
||||
defaultValue: {
|
||||
// Configured values
|
||||
fixed: 'grey',
|
||||
},
|
||||
})
|
||||
.addSliderInput({
|
||||
path: 'config.fillOpacity',
|
||||
name: 'Fill opacity',
|
||||
defaultValue: defaultOptions.fillOpacity,
|
||||
settings: {
|
||||
min: 0,
|
||||
max: 1,
|
||||
step: 0.1,
|
||||
},
|
||||
})
|
||||
.addBooleanSwitch({
|
||||
path: 'config.showLegend',
|
||||
name: 'Show legend',
|
||||
description: 'Show legend',
|
||||
defaultValue: defaultOptions.showLegend,
|
||||
});
|
||||
},
|
||||
|
||||
// fill in the default values
|
||||
defaultOptions,
|
||||
|
||||
@@ -119,44 +119,44 @@ export const textLabelsLayer: MapLayerRegistryItem<TextLabelsConfig> = {
|
||||
const vectorSource = new source.Vector({ features });
|
||||
vectorLayer.setSource(vectorSource);
|
||||
},
|
||||
registerOptionsUI: (builder) => {
|
||||
builder
|
||||
.addCustomEditor({
|
||||
id: 'config.labelText',
|
||||
name: 'Text label',
|
||||
path: 'config.labelText',
|
||||
editor: TextDimensionEditor,
|
||||
})
|
||||
.addCustomEditor({
|
||||
id: 'config.color',
|
||||
path: 'config.color',
|
||||
name: 'Text color',
|
||||
editor: ColorDimensionEditor,
|
||||
settings: {},
|
||||
})
|
||||
.addSliderInput({
|
||||
path: 'config.fillOpacity',
|
||||
name: 'Text opacity',
|
||||
defaultValue: defaultOptions.fillOpacity,
|
||||
settings: {
|
||||
min: 0,
|
||||
max: 1,
|
||||
step: 0.1,
|
||||
},
|
||||
})
|
||||
.addCustomEditor({
|
||||
id: 'config.fontSize',
|
||||
path: 'config.fontSize',
|
||||
name: 'Text size',
|
||||
editor: ScaleDimensionEditor,
|
||||
settings: {
|
||||
fixed: defaultOptions.fontSize.fixed,
|
||||
min: defaultOptions.fontSize.min,
|
||||
max: defaultOptions.fontSize.max,
|
||||
},
|
||||
});
|
||||
},
|
||||
};
|
||||
},
|
||||
registerOptionsUI: (builder) => {
|
||||
builder
|
||||
.addCustomEditor({
|
||||
id: 'config.labelText',
|
||||
name: 'Text label',
|
||||
path: 'config.labelText',
|
||||
editor: TextDimensionEditor,
|
||||
})
|
||||
.addCustomEditor({
|
||||
id: 'config.color',
|
||||
path: 'config.color',
|
||||
name: 'Text color',
|
||||
editor: ColorDimensionEditor,
|
||||
settings: {},
|
||||
})
|
||||
.addSliderInput({
|
||||
path: 'config.fillOpacity',
|
||||
name: 'Text opacity',
|
||||
defaultValue: defaultOptions.fillOpacity,
|
||||
settings: {
|
||||
min: 0,
|
||||
max: 1,
|
||||
step: 0.1,
|
||||
},
|
||||
})
|
||||
.addCustomEditor({
|
||||
id: 'config.fontSize',
|
||||
path: 'config.fontSize',
|
||||
name: 'Text size',
|
||||
editor: ScaleDimensionEditor,
|
||||
settings: {
|
||||
fixed: defaultOptions.fontSize.fixed,
|
||||
min: defaultOptions.fontSize.min,
|
||||
max: defaultOptions.fontSize.max,
|
||||
},
|
||||
});
|
||||
},
|
||||
defaultOptions,
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user