mirror of
https://github.com/grafana/grafana.git
synced 2025-02-03 20:21:01 -06:00
Geomap: Refactor marker style options into reusable component (#41716)
This commit is contained in:
parent
335e0cac11
commit
40d3072df2
@ -63,6 +63,11 @@ export const ResourceDimensionEditor: FC<
|
||||
[onChange, value]
|
||||
);
|
||||
|
||||
const onClear = (event: React.MouseEvent) => {
|
||||
event.stopPropagation();
|
||||
onChange({ mode: ResourceDimensionMode.Fixed, fixed: '', field: '' });
|
||||
};
|
||||
|
||||
const openModal = useCallback(() => {
|
||||
setOpen(true);
|
||||
}, []);
|
||||
@ -71,7 +76,14 @@ export const ResourceDimensionEditor: FC<
|
||||
const showSourceRadio = item.settings?.showSourceRadio ?? true;
|
||||
const mediaType = item.settings?.resourceType ?? 'icon';
|
||||
const folderName = item.settings?.folderName ?? ResourceFolderName.Icon;
|
||||
const srcPath = mediaType === 'icon' && value ? getPublicOrAbsoluteUrl(value?.fixed) : '';
|
||||
let srcPath = '';
|
||||
if (mediaType === 'icon') {
|
||||
if (value?.fixed) {
|
||||
srcPath = getPublicOrAbsoluteUrl(value.fixed);
|
||||
} else if (item.settings?.placeholderValue) {
|
||||
srcPath = getPublicOrAbsoluteUrl(item.settings.placeholderValue);
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
@ -106,15 +118,14 @@ export const ResourceDimensionEditor: FC<
|
||||
</InlineFieldRow>
|
||||
)}
|
||||
{mode === ResourceDimensionMode.Fixed && (
|
||||
<InlineFieldRow>
|
||||
<InlineFieldRow onClick={openModal} className={styles.pointer}>
|
||||
<InlineField label={null} grow>
|
||||
<Input
|
||||
value={niceName(value?.fixed)}
|
||||
placeholder="Resource URL"
|
||||
value={niceName(value?.fixed) ?? ''}
|
||||
placeholder={item.settings?.placeholderText ?? 'Select a value'}
|
||||
readOnly={true}
|
||||
onClick={openModal}
|
||||
prefix={srcPath && <SVG src={srcPath} className={styles.icon} />}
|
||||
suffix={<Button icon="ellipsis-h" variant="secondary" fill="text" size="sm" onClick={openModal} />}
|
||||
suffix={<Button icon="times" variant="secondary" fill="text" size="sm" onClick={onClear} />}
|
||||
/>
|
||||
</InlineField>
|
||||
</InlineFieldRow>
|
||||
@ -148,4 +159,10 @@ const getStyles = (theme: GrafanaTheme2) => ({
|
||||
fill: currentColor;
|
||||
max-width: 25px;
|
||||
`,
|
||||
pointer: css`
|
||||
cursor: pointer;
|
||||
input[readonly] {
|
||||
cursor: pointer;
|
||||
}
|
||||
`,
|
||||
});
|
||||
|
@ -39,8 +39,8 @@ const getFolders = (mediaType: 'icon' | 'image') => {
|
||||
}
|
||||
};
|
||||
|
||||
const folderIfExists = (folders: Array<{ label: string; value: string }>, path: string) => {
|
||||
return folders.filter((folder) => path.indexOf(folder.value) > -1)[0] ?? folders[0];
|
||||
const getFolderIfExists = (folders: Array<SelectableValue<string>>, path: string) => {
|
||||
return folders.find((folder) => path.startsWith(folder.value!)) ?? folders[0];
|
||||
};
|
||||
|
||||
export const ResourcePicker = (props: Props) => {
|
||||
@ -50,8 +50,9 @@ export const ResourcePicker = (props: Props) => {
|
||||
value: v,
|
||||
}));
|
||||
|
||||
const folderOfCurrentValue = value || folderName ? folderIfExists(folders, value ?? folderName) : folders[0];
|
||||
const [currentFolder, setCurrentFolder] = useState<SelectableValue<string>>(folderOfCurrentValue);
|
||||
const [currentFolder, setCurrentFolder] = useState<SelectableValue<string>>(
|
||||
getFolderIfExists(folders, value?.length ? value : folderName)
|
||||
);
|
||||
const [directoryIndex, setDirectoryIndex] = useState<ResourceItem[]>([]);
|
||||
const [filteredIndex, setFilteredIndex] = useState<ResourceItem[]>([]);
|
||||
// select between existing icon folder, url, or upload
|
||||
|
@ -5,8 +5,9 @@ import {
|
||||
StandardEditorsRegistryItem,
|
||||
StringFieldConfigSettings,
|
||||
} from '@grafana/data';
|
||||
import { Button, InlineField, InlineFieldRow, RadioButtonGroup, StringValueEditor } from '@grafana/ui';
|
||||
|
||||
import { TextDimensionConfig, TextDimensionMode, TextDimensionOptions } from '../types';
|
||||
import { InlineField, InlineFieldRow, RadioButtonGroup, StringValueEditor } from '@grafana/ui';
|
||||
import { FieldNamePicker } from '../../../../../packages/grafana-ui/src/components/MatchersUI/FieldNamePicker';
|
||||
|
||||
const textOptions = [
|
||||
@ -57,6 +58,12 @@ export const TextDimensionEditor: FC<StandardEditorProps<TextDimensionConfig, Te
|
||||
[onChange, value]
|
||||
);
|
||||
|
||||
const onClearFixedText = () => {
|
||||
// Need to first change to field in order to clear fixed value in editor
|
||||
onChange({ mode: TextDimensionMode.Field, fixed: '', field: '' });
|
||||
onChange({ mode: TextDimensionMode.Fixed, fixed: '', field: '' });
|
||||
};
|
||||
|
||||
const mode = value?.mode ?? TextDimensionMode.Fixed;
|
||||
|
||||
return (
|
||||
@ -81,12 +88,17 @@ export const TextDimensionEditor: FC<StandardEditorProps<TextDimensionConfig, Te
|
||||
{mode === TextDimensionMode.Fixed && (
|
||||
<InlineFieldRow>
|
||||
<InlineField label={'Value'} labelWidth={labelWidth} grow={true}>
|
||||
<StringValueEditor
|
||||
context={context}
|
||||
value={value?.fixed}
|
||||
onChange={onFixedChange}
|
||||
item={dummyStringSettings}
|
||||
/>
|
||||
<>
|
||||
<StringValueEditor
|
||||
context={context}
|
||||
value={value?.fixed}
|
||||
onChange={onFixedChange}
|
||||
item={dummyStringSettings}
|
||||
/>
|
||||
{value.fixed && (
|
||||
<Button icon="times" variant="secondary" fill="text" size="sm" onClick={onClearFixedText} />
|
||||
)}
|
||||
</>
|
||||
</InlineField>
|
||||
</InlineFieldRow>
|
||||
)}
|
||||
|
@ -65,6 +65,12 @@ export interface TextDimensionConfig extends BaseDimensionConfig<string> {
|
||||
mode: TextDimensionMode;
|
||||
}
|
||||
|
||||
export const defaultTextConfig: TextDimensionConfig = Object.freeze({
|
||||
fixed: '',
|
||||
mode: TextDimensionMode.Field,
|
||||
field: '',
|
||||
});
|
||||
|
||||
/** Use the color value from field configs */
|
||||
export interface ColorDimensionConfig extends BaseDimensionConfig<string> {}
|
||||
|
||||
@ -72,6 +78,9 @@ export interface ColorDimensionConfig extends BaseDimensionConfig<string> {}
|
||||
export interface ResourceDimensionOptions {
|
||||
resourceType: 'icon' | 'image';
|
||||
folderName?: ResourceFolderName;
|
||||
placeholderText?: string;
|
||||
placeholderValue?: string;
|
||||
// If you want your icon to be driven by value of a field
|
||||
showSourceRadio?: boolean;
|
||||
}
|
||||
|
||||
|
185
public/app/plugins/panel/geomap/layers/data/StyleEditor.tsx
Normal file
185
public/app/plugins/panel/geomap/layers/data/StyleEditor.tsx
Normal file
@ -0,0 +1,185 @@
|
||||
import React, { FC } from 'react';
|
||||
import { StandardEditorProps } from '@grafana/data';
|
||||
import { Field, HorizontalGroup, NumberValueEditor, RadioButtonGroup, SliderValueEditor } from '@grafana/ui';
|
||||
|
||||
import {
|
||||
ColorDimensionEditor,
|
||||
ResourceDimensionEditor,
|
||||
ScaleDimensionEditor,
|
||||
TextDimensionEditor,
|
||||
} from 'app/features/dimensions/editors';
|
||||
import {
|
||||
ScaleDimensionConfig,
|
||||
ResourceDimensionConfig,
|
||||
ColorDimensionConfig,
|
||||
ResourceFolderName,
|
||||
TextDimensionConfig,
|
||||
defaultTextConfig,
|
||||
} from 'app/features/dimensions/types';
|
||||
import { defaultStyleConfig, StyleConfig, TextAlignment, TextBaseline } from '../../style/types';
|
||||
|
||||
export const StyleEditor: FC<StandardEditorProps<StyleConfig, any, any>> = ({ value, context, onChange }) => {
|
||||
const onSizeChange = (sizeValue: ScaleDimensionConfig | undefined) => {
|
||||
onChange({ ...value, size: sizeValue });
|
||||
};
|
||||
|
||||
const onSymbolChange = (symbolValue: ResourceDimensionConfig | undefined) => {
|
||||
onChange({ ...value, symbol: symbolValue });
|
||||
};
|
||||
|
||||
const onColorChange = (colorValue: ColorDimensionConfig | undefined) => {
|
||||
onChange({ ...value, color: colorValue });
|
||||
};
|
||||
|
||||
const onOpacityChange = (opacityValue: number | undefined) => {
|
||||
onChange({ ...value, opacity: opacityValue });
|
||||
};
|
||||
|
||||
const onTextChange = (textValue: TextDimensionConfig | undefined) => {
|
||||
onChange({ ...value, text: textValue });
|
||||
};
|
||||
|
||||
const onTextFontSizeChange = (fontSize: number | undefined) => {
|
||||
onChange({ ...value, textConfig: { ...value.textConfig, fontSize } });
|
||||
};
|
||||
|
||||
const onTextOffsetXChange = (offsetX: number | undefined) => {
|
||||
onChange({ ...value, textConfig: { ...value.textConfig, offsetX } });
|
||||
};
|
||||
|
||||
const onTextOffsetYChange = (offsetY: number | undefined) => {
|
||||
onChange({ ...value, textConfig: { ...value.textConfig, offsetY } });
|
||||
};
|
||||
|
||||
const onTextAlignChange = (textAlign: unknown) => {
|
||||
onChange({ ...value, textConfig: { ...value.textConfig, textAlign: textAlign as TextAlignment } });
|
||||
};
|
||||
|
||||
const onTextBaselineChange = (textBaseline: unknown) => {
|
||||
onChange({ ...value, textConfig: { ...value.textConfig, textBaseline: textBaseline as TextBaseline } });
|
||||
};
|
||||
|
||||
const hasTextLabel = Boolean(value.text?.fixed || value.text?.field);
|
||||
|
||||
return (
|
||||
<>
|
||||
<Field label={'Size'}>
|
||||
<ScaleDimensionEditor
|
||||
value={value.size ?? defaultStyleConfig.size}
|
||||
context={context}
|
||||
onChange={onSizeChange}
|
||||
item={
|
||||
{
|
||||
settings: {
|
||||
min: 1,
|
||||
max: 100,
|
||||
},
|
||||
} as any
|
||||
}
|
||||
/>
|
||||
</Field>
|
||||
<Field label={'Symbol'}>
|
||||
<ResourceDimensionEditor
|
||||
value={value.symbol ?? defaultStyleConfig.symbol}
|
||||
context={context}
|
||||
onChange={onSymbolChange}
|
||||
item={
|
||||
{
|
||||
settings: {
|
||||
resourceType: 'icon',
|
||||
folderName: ResourceFolderName.Marker,
|
||||
placeholderText: hasTextLabel ? 'Select a symbol' : 'Select a symbol or add a text label',
|
||||
placeholderValue: defaultStyleConfig.symbol.fixed,
|
||||
showSourceRadio: false,
|
||||
},
|
||||
} as any
|
||||
}
|
||||
/>
|
||||
</Field>
|
||||
<Field label={'Color'}>
|
||||
<ColorDimensionEditor
|
||||
value={value.color ?? defaultStyleConfig.color}
|
||||
context={context}
|
||||
onChange={onColorChange}
|
||||
item={{} as any}
|
||||
/>
|
||||
</Field>
|
||||
<Field label={'Fill opacity'}>
|
||||
<SliderValueEditor
|
||||
value={value.opacity ?? defaultStyleConfig.opacity}
|
||||
context={context}
|
||||
onChange={onOpacityChange}
|
||||
item={
|
||||
{
|
||||
settings: {
|
||||
min: 0,
|
||||
max: 1,
|
||||
step: 0.1,
|
||||
},
|
||||
} as any
|
||||
}
|
||||
/>
|
||||
</Field>
|
||||
<Field label={'Text label'}>
|
||||
<TextDimensionEditor
|
||||
value={value.text ?? defaultTextConfig}
|
||||
context={context}
|
||||
onChange={onTextChange}
|
||||
item={{} as any}
|
||||
/>
|
||||
</Field>
|
||||
{(value.text?.fixed || value.text?.field) && (
|
||||
<>
|
||||
<HorizontalGroup>
|
||||
<Field label={'Font size'}>
|
||||
<NumberValueEditor
|
||||
value={value.textConfig?.fontSize ?? defaultStyleConfig.textConfig.fontSize}
|
||||
context={context}
|
||||
onChange={onTextFontSizeChange}
|
||||
item={{} as any}
|
||||
/>
|
||||
</Field>
|
||||
<Field label={'X offset'}>
|
||||
<NumberValueEditor
|
||||
value={value.textConfig?.offsetX ?? defaultStyleConfig.textConfig.offsetX}
|
||||
context={context}
|
||||
onChange={onTextOffsetXChange}
|
||||
item={{} as any}
|
||||
/>
|
||||
</Field>
|
||||
<Field label={'Y offset'}>
|
||||
<NumberValueEditor
|
||||
value={value.textConfig?.offsetY ?? defaultStyleConfig.textConfig.offsetY}
|
||||
context={context}
|
||||
onChange={onTextOffsetYChange}
|
||||
item={{} as any}
|
||||
/>
|
||||
</Field>
|
||||
</HorizontalGroup>
|
||||
<Field label={'Align'}>
|
||||
<RadioButtonGroup
|
||||
value={value.textConfig?.textAlign ?? defaultStyleConfig.textConfig.textAlign}
|
||||
onChange={onTextAlignChange}
|
||||
options={[
|
||||
{ value: TextAlignment.Left, label: TextAlignment.Left },
|
||||
{ value: TextAlignment.Center, label: TextAlignment.Center },
|
||||
{ value: TextAlignment.Right, label: TextAlignment.Right },
|
||||
]}
|
||||
/>
|
||||
</Field>
|
||||
<Field label={'Baseline'}>
|
||||
<RadioButtonGroup
|
||||
value={value.textConfig?.textBaseline ?? defaultStyleConfig.textConfig.textBaseline}
|
||||
onChange={onTextBaselineChange}
|
||||
options={[
|
||||
{ value: TextBaseline.Top, label: TextBaseline.Top },
|
||||
{ value: TextBaseline.Middle, label: TextBaseline.Middle },
|
||||
{ value: TextBaseline.Bottom, label: TextBaseline.Bottom },
|
||||
]}
|
||||
/>
|
||||
</Field>
|
||||
</>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
};
|
@ -12,19 +12,14 @@ import { Point } from 'ol/geom';
|
||||
import * as layer from 'ol/layer';
|
||||
import * as source from 'ol/source';
|
||||
import { dataFrameToPoints, getLocationMatchers } from '../../utils/location';
|
||||
import {
|
||||
getScaledDimension,
|
||||
getColorDimension,
|
||||
ResourceFolderName,
|
||||
getTextDimension,
|
||||
} from 'app/features/dimensions';
|
||||
import { ScaleDimensionEditor, ColorDimensionEditor, ResourceDimensionEditor, TextDimensionEditor } from 'app/features/dimensions/editors';
|
||||
import { getScaledDimension, getColorDimension, getTextDimension } from 'app/features/dimensions';
|
||||
import { ObservablePropsWrapper } from '../../components/ObservablePropsWrapper';
|
||||
import { MarkersLegend, MarkersLegendProps } from './MarkersLegend';
|
||||
import { ReplaySubject } from 'rxjs';
|
||||
import { FeaturesStylesBuilderConfig, getFeatures } from '../../utils/getFeatures';
|
||||
import { getMarkerMaker } from '../../style/markers';
|
||||
import { defaultStyleConfig, StyleConfig, TextAlignment, TextBaseline } from '../../style/types';
|
||||
import { defaultStyleConfig, StyleConfig } from '../../style/types';
|
||||
import { StyleEditor } from './StyleEditor';
|
||||
|
||||
// Configuration options for Circle overlays
|
||||
export interface MarkersConfig {
|
||||
@ -79,7 +74,8 @@ export const markersLayer: MapLayerRegistryItem<MarkersConfig> = {
|
||||
}
|
||||
|
||||
const style = config.style ?? defaultStyleConfig;
|
||||
const markerMaker = await getMarkerMaker(style.symbol?.fixed);
|
||||
const hasTextLabel = Boolean(style.text?.fixed || style.text?.field);
|
||||
const markerMaker = await getMarkerMaker(style.symbol?.fixed, hasTextLabel);
|
||||
|
||||
return {
|
||||
init: () => vectorLayer,
|
||||
@ -100,7 +96,10 @@ export const markersLayer: MapLayerRegistryItem<MarkersConfig> = {
|
||||
|
||||
const colorDim = getColorDimension(frame, style.color ?? defaultStyleConfig.color, theme);
|
||||
const sizeDim = getScaledDimension(frame, style.size ?? defaultStyleConfig.size);
|
||||
const textDim = style?.text && getTextDimension(frame, style.text);
|
||||
let textDim = undefined;
|
||||
if (style?.text && (style.text.field || style.text.fixed)) {
|
||||
textDim = getTextDimension(frame, style.text);
|
||||
}
|
||||
const opacity = style?.opacity ?? defaultStyleConfig.opacity;
|
||||
|
||||
const featureDimensionConfig: FeaturesStylesBuilderConfig = {
|
||||
@ -137,95 +136,13 @@ export const markersLayer: MapLayerRegistryItem<MarkersConfig> = {
|
||||
registerOptionsUI: (builder) => {
|
||||
builder
|
||||
.addCustomEditor({
|
||||
id: 'config.style.size',
|
||||
path: 'config.style.size',
|
||||
name: 'Marker Size',
|
||||
editor: ScaleDimensionEditor,
|
||||
settings: {
|
||||
min: 1,
|
||||
max: 100, // possible in the UI
|
||||
},
|
||||
defaultValue: defaultOptions.style.size,
|
||||
})
|
||||
.addCustomEditor({
|
||||
id: 'config.style.symbol',
|
||||
path: 'config.style.symbol',
|
||||
name: 'Marker Symbol',
|
||||
editor: ResourceDimensionEditor,
|
||||
defaultValue: defaultOptions.style.symbol,
|
||||
settings: {
|
||||
resourceType: 'icon',
|
||||
showSourceRadio: false,
|
||||
folderName: ResourceFolderName.Marker,
|
||||
},
|
||||
})
|
||||
.addCustomEditor({
|
||||
id: 'config.style.color',
|
||||
path: 'config.style.color',
|
||||
name: 'Marker Color',
|
||||
editor: ColorDimensionEditor,
|
||||
id: 'config.style',
|
||||
path: 'config.style',
|
||||
name: 'Styles',
|
||||
editor: StyleEditor,
|
||||
settings: {},
|
||||
defaultValue: defaultOptions.style.color,
|
||||
defaultValue: defaultOptions.style,
|
||||
})
|
||||
.addSliderInput({
|
||||
path: 'config.style.opacity',
|
||||
name: 'Fill opacity',
|
||||
defaultValue: defaultOptions.style.opacity,
|
||||
settings: {
|
||||
min: 0,
|
||||
max: 1,
|
||||
step: 0.1,
|
||||
},
|
||||
})
|
||||
.addCustomEditor({
|
||||
id: 'config.style.text',
|
||||
path: 'config.style.text',
|
||||
name: 'Text label',
|
||||
editor: TextDimensionEditor,
|
||||
defaultValue: defaultOptions.style.text,
|
||||
})
|
||||
.addNumberInput({
|
||||
name: 'Text font size',
|
||||
path: 'config.style.textConfig.fontSize',
|
||||
defaultValue: defaultOptions.style.textConfig?.fontSize,
|
||||
})
|
||||
.addNumberInput({
|
||||
name: 'Text X offset',
|
||||
path: 'config.style.textConfig.offsetX',
|
||||
defaultValue: 0,
|
||||
})
|
||||
.addNumberInput({
|
||||
name: 'Text Y offset',
|
||||
path: 'config.style.textConfig.offsetY',
|
||||
defaultValue: 0,
|
||||
})
|
||||
.addRadio({
|
||||
name: 'Text align',
|
||||
path: 'config.style.textConfig.textAlign',
|
||||
description: '',
|
||||
defaultValue: defaultOptions.style.textConfig?.textAlign,
|
||||
settings: {
|
||||
options: [
|
||||
{ value: TextAlignment.Left, label: TextAlignment.Left },
|
||||
{ value: TextAlignment.Center, label: TextAlignment.Center },
|
||||
{ value: TextAlignment.Right, label: TextAlignment.Right },
|
||||
],
|
||||
},
|
||||
})
|
||||
.addRadio({
|
||||
name: 'Text baseline',
|
||||
path: 'config.style.textConfig.textBaseline',
|
||||
description: '',
|
||||
defaultValue: defaultOptions.style.textConfig?.textBaseline,
|
||||
settings: {
|
||||
options: [
|
||||
{ value: TextBaseline.Top, label: TextBaseline.Top },
|
||||
{ value: TextBaseline.Middle, label: TextBaseline.Middle },
|
||||
{ value: TextBaseline.Bottom, label: TextBaseline.Bottom },
|
||||
],
|
||||
},
|
||||
})
|
||||
// baseline?: 'bottom' | 'top' | 'middle';
|
||||
.addBooleanSwitch({
|
||||
path: 'config.showLegend',
|
||||
name: 'Show legend',
|
||||
|
@ -162,6 +162,8 @@ describe('geomap migrations', () => {
|
||||
},
|
||||
"textConfig": Object {
|
||||
"fontSize": 12,
|
||||
"offsetX": 0,
|
||||
"offsetY": 0,
|
||||
"textAlign": "center",
|
||||
"textBaseline": "middle",
|
||||
},
|
||||
|
@ -41,19 +41,29 @@ export function getFillColor(cfg: StyleConfigValues) {
|
||||
}
|
||||
|
||||
const textLabel = (cfg: StyleConfigValues) => {
|
||||
if (!cfg.text) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const fontFamily = config.theme2.typography.fontFamily;
|
||||
const textConfig = {
|
||||
...defaultStyleConfig.textConfig,
|
||||
...cfg.textConfig,
|
||||
};
|
||||
return new Text({
|
||||
text: cfg.text ?? '?',
|
||||
text: cfg.text,
|
||||
fill: new Fill({ color: cfg.color ?? defaultStyleConfig.color.fixed }),
|
||||
font: `normal ${textConfig.fontSize}px ${fontFamily}`,
|
||||
...textConfig,
|
||||
});
|
||||
};
|
||||
|
||||
export const textMarker = (cfg: StyleConfigValues) => {
|
||||
return new Style({
|
||||
text: textLabel(cfg),
|
||||
});
|
||||
};
|
||||
|
||||
export const circleMarker = (cfg: StyleConfigValues) => {
|
||||
return new Style({
|
||||
image: new Circle({
|
||||
@ -227,9 +237,9 @@ export function getMarkerAsPath(shape?: string): string | undefined {
|
||||
}
|
||||
|
||||
// Will prepare symbols as necessary
|
||||
export async function getMarkerMaker(symbol?: string): Promise<StyleMaker> {
|
||||
export async function getMarkerMaker(symbol?: string, hasTextLabel?: boolean): Promise<StyleMaker> {
|
||||
if (!symbol) {
|
||||
return circleMarker;
|
||||
return hasTextLabel ? textMarker : circleMarker;
|
||||
}
|
||||
|
||||
let maker = markerMakers.getIfExists(symbol);
|
||||
@ -274,6 +284,6 @@ export async function getMarkerMaker(symbol?: string): Promise<StyleMaker> {
|
||||
return maker.make;
|
||||
}
|
||||
|
||||
// defatult to showing a circle
|
||||
// default to showing a circle
|
||||
return errorMarker;
|
||||
}
|
||||
|
@ -62,6 +62,8 @@ export const defaultStyleConfig = Object.freeze({
|
||||
fontSize: 12,
|
||||
textAlign: TextAlignment.Center,
|
||||
textBaseline: TextBaseline.Middle,
|
||||
offsetX: 0,
|
||||
offsetY: 0,
|
||||
},
|
||||
});
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user