Geomap: use same style config for makers and geojson (#41846)

This commit is contained in:
Ryan McKinley
2021-11-17 22:13:27 -08:00
committed by GitHub
parent 18cc552edb
commit 837e268395
8 changed files with 183 additions and 116 deletions

View File

@@ -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'}>

View File

@@ -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,
});
},
};

View File

@@ -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,
];