mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
Geomap: use same style config for makers and geojson (#41846)
This commit is contained in:
@@ -1,6 +1,16 @@
|
||||
import React, { FC } from 'react';
|
||||
import { StandardEditorProps } from '@grafana/data';
|
||||
import { Field, HorizontalGroup, NumberValueEditor, RadioButtonGroup, SliderValueEditor } from '@grafana/ui';
|
||||
import {
|
||||
ColorPicker,
|
||||
Field,
|
||||
HorizontalGroup,
|
||||
InlineField,
|
||||
InlineFieldRow,
|
||||
InlineLabel,
|
||||
NumberValueEditor,
|
||||
RadioButtonGroup,
|
||||
SliderValueEditor,
|
||||
} from '@grafana/ui';
|
||||
|
||||
import {
|
||||
ColorDimensionEditor,
|
||||
@@ -17,8 +27,18 @@ import {
|
||||
defaultTextConfig,
|
||||
} from 'app/features/dimensions/types';
|
||||
import { defaultStyleConfig, StyleConfig, TextAlignment, TextBaseline } from '../../style/types';
|
||||
import { styleUsesText } from '../../style/utils';
|
||||
|
||||
export const StyleEditor: FC<StandardEditorProps<StyleConfig, any, any>> = ({ value, context, onChange }) => {
|
||||
export interface StyleEditorOptions {
|
||||
simpleFixedValues?: boolean;
|
||||
}
|
||||
|
||||
export const StyleEditor: FC<StandardEditorProps<StyleConfig, StyleEditorOptions, any>> = ({
|
||||
value,
|
||||
context,
|
||||
onChange,
|
||||
item,
|
||||
}) => {
|
||||
const onSizeChange = (sizeValue: ScaleDimensionConfig | undefined) => {
|
||||
onChange({ ...value, size: sizeValue });
|
||||
};
|
||||
@@ -59,7 +79,45 @@ export const StyleEditor: FC<StandardEditorProps<StyleConfig, any, any>> = ({ va
|
||||
onChange({ ...value, textConfig: { ...value.textConfig, textBaseline: textBaseline as TextBaseline } });
|
||||
};
|
||||
|
||||
const hasTextLabel = Boolean(value.text?.fixed || value.text?.field);
|
||||
// Simple fixed value display
|
||||
if (item.settings?.simpleFixedValues) {
|
||||
return (
|
||||
<>
|
||||
<InlineFieldRow>
|
||||
<InlineField label="Color" labelWidth={10}>
|
||||
<InlineLabel width={4}>
|
||||
<ColorPicker
|
||||
color={value.color?.fixed ?? defaultStyleConfig.color.fixed}
|
||||
onChange={(v) => {
|
||||
onColorChange({ fixed: v });
|
||||
}}
|
||||
/>
|
||||
</InlineLabel>
|
||||
</InlineField>
|
||||
</InlineFieldRow>
|
||||
<InlineFieldRow>
|
||||
<InlineField label="Opacity" labelWidth={10} grow={true}>
|
||||
<SliderValueEditor
|
||||
value={value.opacity ?? defaultStyleConfig.opacity}
|
||||
context={context}
|
||||
onChange={onOpacityChange}
|
||||
item={
|
||||
{
|
||||
settings: {
|
||||
min: 0,
|
||||
max: 1,
|
||||
step: 0.1,
|
||||
},
|
||||
} as any
|
||||
}
|
||||
/>
|
||||
</InlineField>
|
||||
</InlineFieldRow>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
const hasTextLabel = styleUsesText(value);
|
||||
|
||||
return (
|
||||
<>
|
||||
@@ -128,7 +186,8 @@ export const StyleEditor: FC<StandardEditorProps<StyleConfig, any, any>> = ({ va
|
||||
item={{} as any}
|
||||
/>
|
||||
</Field>
|
||||
{(value.text?.fixed || value.text?.field) && (
|
||||
|
||||
{hasTextLabel && (
|
||||
<>
|
||||
<HorizontalGroup>
|
||||
<Field label={'Font size'}>
|
||||
|
||||
@@ -4,44 +4,53 @@ 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';
|
||||
import { checkFeatureMatchesStyleRule } from '../../utils/checkFeatureMatchesStyleRule';
|
||||
import { ComparisonOperation, FeatureStyleConfig } from '../../types';
|
||||
import { Stroke, Style } from 'ol/style';
|
||||
import { ComparisonOperation, FeatureRuleConfig, FeatureStyleConfig } from '../../types';
|
||||
import { Style } from 'ol/style';
|
||||
import { FeatureLike } from 'ol/Feature';
|
||||
import { GeomapStyleRulesEditor } from '../../editor/GeomapStyleRulesEditor';
|
||||
import { circleMarker } from '../../style/markers';
|
||||
import { defaultStyleConfig, StyleConfig } from '../../style/types';
|
||||
import { getStyleConfigState } from '../../style/utils';
|
||||
import { polyStyle } from '../../style/markers';
|
||||
import { StyleEditor } from './StyleEditor';
|
||||
export interface GeoJSONMapperConfig {
|
||||
// URL for a geojson file
|
||||
src?: string;
|
||||
|
||||
// Styles that can be applied
|
||||
styles: FeatureStyleConfig[];
|
||||
// Pick style based on a rule
|
||||
rules: FeatureStyleConfig[];
|
||||
|
||||
// The default style (applied if no rules match)
|
||||
style: StyleConfig;
|
||||
}
|
||||
|
||||
const defaultOptions: GeoJSONMapperConfig = {
|
||||
src: 'public/maps/countries.geojson',
|
||||
styles: [],
|
||||
rules: [],
|
||||
style: defaultStyleConfig,
|
||||
};
|
||||
|
||||
interface StyleCheckerState {
|
||||
poly: Style | Style[];
|
||||
point: Style | Style[];
|
||||
rule?: FeatureRuleConfig;
|
||||
}
|
||||
|
||||
export const DEFAULT_STYLE_RULE: FeatureStyleConfig = {
|
||||
fillColor: '#1F60C4',
|
||||
strokeWidth: 1,
|
||||
rule: {
|
||||
style: defaultStyleConfig,
|
||||
check: {
|
||||
property: '',
|
||||
operation: ComparisonOperation.EQ,
|
||||
value: '',
|
||||
},
|
||||
};
|
||||
|
||||
export const geojsonMapper: MapLayerRegistryItem<GeoJSONMapperConfig> = {
|
||||
id: 'geojson-value-mapper',
|
||||
name: 'Map values to GeoJSON file',
|
||||
description: 'color features based on query results',
|
||||
export const geojsonLayer: MapLayerRegistryItem<GeoJSONMapperConfig> = {
|
||||
id: 'geojson',
|
||||
name: 'GeoJSON',
|
||||
description: 'Load static data from a geojson file',
|
||||
isBaseMap: false,
|
||||
state: PluginState.alpha,
|
||||
state: PluginState.beta,
|
||||
|
||||
/**
|
||||
* Function that configures transformation and returns a transformer
|
||||
@@ -68,30 +77,39 @@ export const geojsonMapper: MapLayerRegistryItem<GeoJSONMapperConfig> = {
|
||||
}
|
||||
});
|
||||
|
||||
const defaultStyle = new Style({
|
||||
stroke: new Stroke({
|
||||
color: DEFAULT_STYLE_RULE.fillColor,
|
||||
width: DEFAULT_STYLE_RULE.strokeWidth,
|
||||
}),
|
||||
});
|
||||
const styles: StyleCheckerState[] = [];
|
||||
if (config.rules) {
|
||||
for (const r of config.rules) {
|
||||
if (r.style) {
|
||||
const s = await getStyleConfigState(r.style);
|
||||
styles.push({
|
||||
point: s.maker(s.base),
|
||||
poly: polyStyle(s.base),
|
||||
rule: r.check,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
if (true) {
|
||||
const s = await getStyleConfigState(config.style);
|
||||
styles.push({
|
||||
point: s.maker(s.base),
|
||||
poly: polyStyle(s.base),
|
||||
});
|
||||
}
|
||||
|
||||
const vectorLayer = new VectorLayer({
|
||||
source,
|
||||
style: (feature: FeatureLike) => {
|
||||
const type = feature.getGeometry()?.getType();
|
||||
if (type === 'Point') {
|
||||
return circleMarker({color:DEFAULT_STYLE_RULE.fillColor});
|
||||
}
|
||||
const isPoint = feature.getGeometry()?.getType() === 'Point';
|
||||
|
||||
if (feature && config?.styles?.length) {
|
||||
for (const style of config.styles) {
|
||||
//check if there is no style rule or if the rule matches feature property
|
||||
if (!style.rule || checkFeatureMatchesStyleRule(style.rule, feature as Feature<Geometry>)) {
|
||||
return getGeoMapStyle(style, feature);
|
||||
}
|
||||
for (const check of styles) {
|
||||
if (check.rule && !checkFeatureMatchesStyleRule(check.rule, feature)) {
|
||||
continue;
|
||||
}
|
||||
return isPoint ? check.point : check.poly;
|
||||
}
|
||||
return defaultStyle;
|
||||
return undefined; // unreachable
|
||||
},
|
||||
});
|
||||
|
||||
@@ -126,12 +144,24 @@ export const geojsonMapper: MapLayerRegistryItem<GeoJSONMapperConfig> = {
|
||||
defaultValue: defaultOptions.src,
|
||||
})
|
||||
.addCustomEditor({
|
||||
id: 'config.styles',
|
||||
path: 'config.styles',
|
||||
id: 'config.rules',
|
||||
path: 'config.rules',
|
||||
name: 'Style Rules',
|
||||
description: 'Apply styles based on feature properties',
|
||||
editor: GeomapStyleRulesEditor,
|
||||
settings: {},
|
||||
defaultValue: [],
|
||||
})
|
||||
.addCustomEditor({
|
||||
id: 'config.style',
|
||||
path: 'config.style',
|
||||
name: 'Default Style',
|
||||
description: 'The style to apply when no rules above match',
|
||||
editor: StyleEditor,
|
||||
settings: {
|
||||
simpleFixedValues: true,
|
||||
},
|
||||
defaultValue: defaultOptions.style,
|
||||
});
|
||||
},
|
||||
};
|
||||
@@ -1,5 +1,5 @@
|
||||
import { markersLayer } from './markersLayer';
|
||||
import { geojsonMapper } from './geojsonMapper';
|
||||
import { geojsonLayer } from './geojsonLayer';
|
||||
import { heatmapLayer } from './heatMap';
|
||||
import { lastPointTracker } from './lastPointTracker';
|
||||
|
||||
@@ -10,5 +10,5 @@ export const dataLayers = [
|
||||
markersLayer,
|
||||
heatmapLayer,
|
||||
lastPointTracker,
|
||||
geojsonMapper, // dummy for now
|
||||
geojsonLayer,
|
||||
];
|
||||
|
||||
Reference in New Issue
Block a user