mirror of
https://github.com/grafana/grafana.git
synced 2025-08-06 20:59:35 +08:00
Geomap: Combine Text layer with Markers Layer and add text options (#41768)
* add text to markers * add textConfig * remove separate text layer * update test * Update public/app/plugins/panel/geomap/style/markers.ts Co-authored-by: Ryan McKinley <ryantxu@gmail.com> * Update public/app/plugins/panel/geomap/style/markers.ts Co-authored-by: Ryan McKinley <ryantxu@gmail.com> * update textConfig naming Co-authored-by: Ryan McKinley <ryantxu@gmail.com>
This commit is contained in:
@ -2,7 +2,6 @@ import { markersLayer } from './markersLayer';
|
|||||||
import { geojsonMapper } from './geojsonMapper';
|
import { geojsonMapper } from './geojsonMapper';
|
||||||
import { heatmapLayer } from './heatMap';
|
import { heatmapLayer } from './heatMap';
|
||||||
import { lastPointTracker } from './lastPointTracker';
|
import { lastPointTracker } from './lastPointTracker';
|
||||||
import { textLabelsLayer } from './textLabelsLayer';
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Registry for layer handlers
|
* Registry for layer handlers
|
||||||
@ -12,5 +11,4 @@ export const dataLayers = [
|
|||||||
heatmapLayer,
|
heatmapLayer,
|
||||||
lastPointTracker,
|
lastPointTracker,
|
||||||
geojsonMapper, // dummy for now
|
geojsonMapper, // dummy for now
|
||||||
textLabelsLayer,
|
|
||||||
];
|
];
|
||||||
|
@ -16,14 +16,15 @@ import {
|
|||||||
getScaledDimension,
|
getScaledDimension,
|
||||||
getColorDimension,
|
getColorDimension,
|
||||||
ResourceFolderName,
|
ResourceFolderName,
|
||||||
|
getTextDimension,
|
||||||
} from 'app/features/dimensions';
|
} from 'app/features/dimensions';
|
||||||
import { ScaleDimensionEditor, ColorDimensionEditor, ResourceDimensionEditor } from 'app/features/dimensions/editors';
|
import { ScaleDimensionEditor, ColorDimensionEditor, ResourceDimensionEditor, TextDimensionEditor } from 'app/features/dimensions/editors';
|
||||||
import { ObservablePropsWrapper } from '../../components/ObservablePropsWrapper';
|
import { ObservablePropsWrapper } from '../../components/ObservablePropsWrapper';
|
||||||
import { MarkersLegend, MarkersLegendProps } from './MarkersLegend';
|
import { MarkersLegend, MarkersLegendProps } from './MarkersLegend';
|
||||||
import { ReplaySubject } from 'rxjs';
|
import { ReplaySubject } from 'rxjs';
|
||||||
import { FeaturesStylesBuilderConfig, getFeatures } from '../../utils/getFeatures';
|
import { FeaturesStylesBuilderConfig, getFeatures } from '../../utils/getFeatures';
|
||||||
import { getMarkerMaker } from '../../style/markers';
|
import { getMarkerMaker } from '../../style/markers';
|
||||||
import { defaultStyleConfig, StyleConfig } from '../../style/types';
|
import { defaultStyleConfig, StyleConfig, TextAlignment, TextBaseline } from '../../style/types';
|
||||||
|
|
||||||
// Configuration options for Circle overlays
|
// Configuration options for Circle overlays
|
||||||
export interface MarkersConfig {
|
export interface MarkersConfig {
|
||||||
@ -99,11 +100,14 @@ export const markersLayer: MapLayerRegistryItem<MarkersConfig> = {
|
|||||||
|
|
||||||
const colorDim = getColorDimension(frame, style.color ?? defaultStyleConfig.color, theme);
|
const colorDim = getColorDimension(frame, style.color ?? defaultStyleConfig.color, theme);
|
||||||
const sizeDim = getScaledDimension(frame, style.size ?? defaultStyleConfig.size);
|
const sizeDim = getScaledDimension(frame, style.size ?? defaultStyleConfig.size);
|
||||||
|
const textDim = style?.text && getTextDimension(frame, style.text);
|
||||||
const opacity = style?.opacity ?? defaultStyleConfig.opacity;
|
const opacity = style?.opacity ?? defaultStyleConfig.opacity;
|
||||||
|
|
||||||
const featureDimensionConfig: FeaturesStylesBuilderConfig = {
|
const featureDimensionConfig: FeaturesStylesBuilderConfig = {
|
||||||
colorDim: colorDim,
|
colorDim: colorDim,
|
||||||
sizeDim: sizeDim,
|
sizeDim: sizeDim,
|
||||||
|
textDim: textDim,
|
||||||
|
textConfig: style?.textConfig,
|
||||||
opacity: opacity,
|
opacity: opacity,
|
||||||
styleMaker: markerMaker,
|
styleMaker: markerMaker,
|
||||||
};
|
};
|
||||||
@ -173,6 +177,55 @@ export const markersLayer: MapLayerRegistryItem<MarkersConfig> = {
|
|||||||
step: 0.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({
|
.addBooleanSwitch({
|
||||||
path: 'config.showLegend',
|
path: 'config.showLegend',
|
||||||
name: 'Show legend',
|
name: 'Show legend',
|
||||||
|
@ -1,146 +0,0 @@
|
|||||||
import { GrafanaTheme2, MapLayerOptions, MapLayerRegistryItem, PanelData, PluginState } from '@grafana/data';
|
|
||||||
import Map from 'ol/Map';
|
|
||||||
import * as layer from 'ol/layer';
|
|
||||||
import * as source from 'ol/source';
|
|
||||||
import { dataFrameToPoints, getLocationMatchers } from '../../utils/location';
|
|
||||||
import {
|
|
||||||
getColorDimension,
|
|
||||||
getScaledDimension,
|
|
||||||
getTextDimension,
|
|
||||||
TextDimensionMode,
|
|
||||||
} from 'app/features/dimensions';
|
|
||||||
import { ColorDimensionEditor, ScaleDimensionEditor, TextDimensionEditor } from 'app/features/dimensions/editors';
|
|
||||||
import { FeaturesStylesBuilderConfig, getFeatures } from '../../utils/getFeatures';
|
|
||||||
import { Feature } from 'ol';
|
|
||||||
import { Point } from 'ol/geom';
|
|
||||||
import { textMarkerMaker } from '../../style/text';
|
|
||||||
import { MarkersConfig } from './markersLayer';
|
|
||||||
|
|
||||||
|
|
||||||
export const TEXT_LABELS_LAYER = 'text-labels';
|
|
||||||
|
|
||||||
// Same configuration
|
|
||||||
type TextLabelsConfig = MarkersConfig;
|
|
||||||
|
|
||||||
const defaultOptions = {
|
|
||||||
style: {
|
|
||||||
text: {
|
|
||||||
fixed: '',
|
|
||||||
mode: TextDimensionMode.Field,
|
|
||||||
},
|
|
||||||
color: {
|
|
||||||
fixed: 'dark-blue',
|
|
||||||
},
|
|
||||||
opacity: 1,
|
|
||||||
size: {
|
|
||||||
fixed: 10,
|
|
||||||
min: 5,
|
|
||||||
max: 100,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
showLegend: false,
|
|
||||||
};
|
|
||||||
|
|
||||||
export const textLabelsLayer: MapLayerRegistryItem<TextLabelsConfig> = {
|
|
||||||
id: TEXT_LABELS_LAYER,
|
|
||||||
name: 'Text labels',
|
|
||||||
description: 'render text labels',
|
|
||||||
isBaseMap: false,
|
|
||||||
state: PluginState.alpha,
|
|
||||||
showLocation: true,
|
|
||||||
|
|
||||||
create: async (map: Map, options: MapLayerOptions<TextLabelsConfig>, theme: GrafanaTheme2) => {
|
|
||||||
const matchers = await getLocationMatchers(options.location);
|
|
||||||
const vectorLayer = new layer.Vector({});
|
|
||||||
|
|
||||||
const config = {
|
|
||||||
...defaultOptions,
|
|
||||||
...options?.config,
|
|
||||||
};
|
|
||||||
|
|
||||||
return {
|
|
||||||
init: () => vectorLayer,
|
|
||||||
update: (data: PanelData) => {
|
|
||||||
if (!data.series?.length) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const features: Feature<Point>[] = [];
|
|
||||||
|
|
||||||
|
|
||||||
const style = config.style ?? defaultOptions.style;
|
|
||||||
|
|
||||||
for (const frame of data.series) {
|
|
||||||
const info = dataFrameToPoints(frame, matchers);
|
|
||||||
if (info.warning) {
|
|
||||||
console.log('Could not find locations', info.warning);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const colorDim = getColorDimension(frame, style.color ?? defaultOptions.style.color, theme);
|
|
||||||
const sizeDim = getScaledDimension(frame, style.size ?? defaultOptions.style.size);
|
|
||||||
const opacity = style?.opacity ?? defaultOptions.style.opacity;
|
|
||||||
const textDim = getTextDimension(frame, style.text ?? defaultOptions.style.text );
|
|
||||||
|
|
||||||
const featureDimensionConfig: FeaturesStylesBuilderConfig = {
|
|
||||||
colorDim: colorDim,
|
|
||||||
sizeDim: sizeDim,
|
|
||||||
textDim: textDim,
|
|
||||||
opacity: opacity,
|
|
||||||
styleMaker: textMarkerMaker,
|
|
||||||
};
|
|
||||||
|
|
||||||
const frameFeatures = getFeatures(frame, info, featureDimensionConfig);
|
|
||||||
|
|
||||||
if (frameFeatures) {
|
|
||||||
features.push(...frameFeatures);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Source reads the data and provides a set of features to visualize
|
|
||||||
const vectorSource = new source.Vector({ features });
|
|
||||||
vectorLayer.setSource(vectorSource);
|
|
||||||
},
|
|
||||||
registerOptionsUI: (builder) => {
|
|
||||||
builder
|
|
||||||
.addCustomEditor({
|
|
||||||
id: 'config.style.text',
|
|
||||||
path: 'config.style.text',
|
|
||||||
name: 'Text label',
|
|
||||||
editor: TextDimensionEditor,
|
|
||||||
defaultValue: defaultOptions.style.text,
|
|
||||||
})
|
|
||||||
.addCustomEditor({
|
|
||||||
id: 'config.style.color',
|
|
||||||
path: 'config.style.color',
|
|
||||||
name: 'Text color',
|
|
||||||
editor: ColorDimensionEditor,
|
|
||||||
defaultValue: defaultOptions.style.color,
|
|
||||||
settings: {},
|
|
||||||
})
|
|
||||||
.addSliderInput({
|
|
||||||
path: 'config.style.opacity',
|
|
||||||
name: 'Text opacity',
|
|
||||||
defaultValue: defaultOptions.style.opacity,
|
|
||||||
settings: {
|
|
||||||
min: 0,
|
|
||||||
max: 1,
|
|
||||||
step: 0.1,
|
|
||||||
},
|
|
||||||
})
|
|
||||||
.addCustomEditor({
|
|
||||||
id: 'config.style.size',
|
|
||||||
path: 'config.style.size',
|
|
||||||
name: 'Text size',
|
|
||||||
editor: ScaleDimensionEditor,
|
|
||||||
defaultValue: defaultOptions.style.size,
|
|
||||||
settings: {
|
|
||||||
min: 2,
|
|
||||||
max: 50,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
},
|
|
||||||
};
|
|
||||||
},
|
|
||||||
defaultOptions,
|
|
||||||
};
|
|
@ -160,6 +160,11 @@ describe('geomap migrations', () => {
|
|||||||
"fixed": "img/icons/marker/triangle.svg",
|
"fixed": "img/icons/marker/triangle.svg",
|
||||||
"mode": "fixed",
|
"mode": "fixed",
|
||||||
},
|
},
|
||||||
|
"textConfig": Object {
|
||||||
|
"fontSize": 12,
|
||||||
|
"textAlign": "center",
|
||||||
|
"textBaseline": "middle",
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
"type": "markers",
|
"type": "markers",
|
||||||
|
@ -1,8 +1,9 @@
|
|||||||
import { Fill, RegularShape, Stroke, Circle, Style, Icon } from 'ol/style';
|
import { Fill, RegularShape, Stroke, Circle, Style, Icon, Text } from 'ol/style';
|
||||||
import { Registry, RegistryItem } from '@grafana/data';
|
import { Registry, RegistryItem } from '@grafana/data';
|
||||||
import { DEFAULT_SIZE, StyleConfigValues, StyleMaker } from './types';
|
import { defaultStyleConfig, DEFAULT_SIZE, StyleConfigValues, StyleMaker } from './types';
|
||||||
import { getPublicOrAbsoluteUrl } from 'app/features/dimensions';
|
import { getPublicOrAbsoluteUrl } from 'app/features/dimensions';
|
||||||
import tinycolor from 'tinycolor2';
|
import tinycolor from 'tinycolor2';
|
||||||
|
import { config } from '@grafana/runtime';
|
||||||
|
|
||||||
interface SymbolMaker extends RegistryItem {
|
interface SymbolMaker extends RegistryItem {
|
||||||
aliasIds: string[];
|
aliasIds: string[];
|
||||||
@ -39,6 +40,20 @@ export function getFillColor(cfg: StyleConfigValues) {
|
|||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const textLabel = (cfg: StyleConfigValues) => {
|
||||||
|
const fontFamily = config.theme2.typography.fontFamily;
|
||||||
|
const textConfig = {
|
||||||
|
...defaultStyleConfig.textConfig,
|
||||||
|
...cfg.textConfig,
|
||||||
|
};
|
||||||
|
return new Text({
|
||||||
|
text: cfg.text ?? '?',
|
||||||
|
fill: new Fill({ color: cfg.color ?? defaultStyleConfig.color.fixed }),
|
||||||
|
font: `normal ${textConfig.fontSize}px ${fontFamily}`,
|
||||||
|
...textConfig,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
export const circleMarker = (cfg: StyleConfigValues) => {
|
export const circleMarker = (cfg: StyleConfigValues) => {
|
||||||
return new Style({
|
return new Style({
|
||||||
image: new Circle({
|
image: new Circle({
|
||||||
@ -46,6 +61,7 @@ export const circleMarker = (cfg: StyleConfigValues) => {
|
|||||||
fill: getFillColor(cfg),
|
fill: getFillColor(cfg),
|
||||||
radius: cfg.size ?? DEFAULT_SIZE,
|
radius: cfg.size ?? DEFAULT_SIZE,
|
||||||
}),
|
}),
|
||||||
|
text: textLabel(cfg),
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -95,6 +111,7 @@ const makers: SymbolMaker[] = [
|
|||||||
radius,
|
radius,
|
||||||
angle: Math.PI / 4,
|
angle: Math.PI / 4,
|
||||||
}),
|
}),
|
||||||
|
text: textLabel(cfg),
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -113,6 +130,7 @@ const makers: SymbolMaker[] = [
|
|||||||
rotation: Math.PI / 4,
|
rotation: Math.PI / 4,
|
||||||
angle: 0,
|
angle: 0,
|
||||||
}),
|
}),
|
||||||
|
text: textLabel(cfg),
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -131,6 +149,7 @@ const makers: SymbolMaker[] = [
|
|||||||
radius2: radius * 0.4,
|
radius2: radius * 0.4,
|
||||||
angle: 0,
|
angle: 0,
|
||||||
}),
|
}),
|
||||||
|
text: textLabel(cfg),
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -148,6 +167,7 @@ const makers: SymbolMaker[] = [
|
|||||||
radius2: 0,
|
radius2: 0,
|
||||||
angle: 0,
|
angle: 0,
|
||||||
}),
|
}),
|
||||||
|
text: textLabel(cfg),
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -165,6 +185,7 @@ const makers: SymbolMaker[] = [
|
|||||||
radius2: 0,
|
radius2: 0,
|
||||||
angle: Math.PI / 4,
|
angle: Math.PI / 4,
|
||||||
}),
|
}),
|
||||||
|
text: textLabel(cfg),
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -234,6 +255,7 @@ export async function getMarkerMaker(symbol?: string): Promise<StyleMaker> {
|
|||||||
opacity: cfg.opacity ?? 1,
|
opacity: cfg.opacity ?? 1,
|
||||||
scale: (DEFAULT_SIZE + radius) / 100,
|
scale: (DEFAULT_SIZE + radius) / 100,
|
||||||
}),
|
}),
|
||||||
|
text: !cfg?.text ? undefined : textLabel(cfg),
|
||||||
}),
|
}),
|
||||||
// transparent bounding box for featureAtPixel detection
|
// transparent bounding box for featureAtPixel detection
|
||||||
new Style({
|
new Style({
|
||||||
|
@ -1,16 +0,0 @@
|
|||||||
import { Style, Text } from 'ol/style';
|
|
||||||
import { config } from '@grafana/runtime';
|
|
||||||
import { StyleConfigValues, StyleMaker } from './types';
|
|
||||||
import { getFillColor } from './markers';
|
|
||||||
|
|
||||||
export const textMarkerMaker: StyleMaker = (cfg: StyleConfigValues) => {
|
|
||||||
const fontFamily = config.theme2.typography.fontFamily;
|
|
||||||
const fontSize = cfg.size ?? 12;
|
|
||||||
return new Style({
|
|
||||||
text: new Text({
|
|
||||||
text: cfg.text ?? '?',
|
|
||||||
fill: getFillColor(cfg),
|
|
||||||
font: `normal ${fontSize}px ${fontFamily}`,
|
|
||||||
}),
|
|
||||||
});
|
|
||||||
};
|
|
@ -33,6 +33,17 @@ export interface StyleConfig {
|
|||||||
|
|
||||||
export const DEFAULT_SIZE = 5;
|
export const DEFAULT_SIZE = 5;
|
||||||
|
|
||||||
|
export enum TextAlignment {
|
||||||
|
Left = 'left',
|
||||||
|
Center = 'center',
|
||||||
|
Right = 'right',
|
||||||
|
}
|
||||||
|
export enum TextBaseline {
|
||||||
|
Top = 'top',
|
||||||
|
Middle = 'middle',
|
||||||
|
Bottom = 'bottom',
|
||||||
|
}
|
||||||
|
|
||||||
export const defaultStyleConfig = Object.freeze({
|
export const defaultStyleConfig = Object.freeze({
|
||||||
size: {
|
size: {
|
||||||
fixed: DEFAULT_SIZE,
|
fixed: DEFAULT_SIZE,
|
||||||
@ -47,6 +58,11 @@ export const defaultStyleConfig = Object.freeze({
|
|||||||
mode: ResourceDimensionMode.Fixed,
|
mode: ResourceDimensionMode.Fixed,
|
||||||
fixed: 'img/icons/marker/circle.svg',
|
fixed: 'img/icons/marker/circle.svg',
|
||||||
},
|
},
|
||||||
|
textConfig: {
|
||||||
|
fontSize: 12,
|
||||||
|
textAlign: TextAlignment.Center,
|
||||||
|
textBaseline: TextBaseline.Middle,
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -57,8 +73,8 @@ export interface TextStyleConfig {
|
|||||||
fontSize?: number;
|
fontSize?: number;
|
||||||
offsetX?: number;
|
offsetX?: number;
|
||||||
offsetY?: number;
|
offsetY?: number;
|
||||||
align?: 'left' | 'right' | 'center';
|
textAlign?: TextAlignment;
|
||||||
baseline?: 'bottom' | 'top' | 'middle';
|
textBaseline?: TextBaseline;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Applying the config to real data gives the values
|
// Applying the config to real data gives the values
|
||||||
|
@ -2,7 +2,7 @@ import { DataFrame } from '@grafana/data';
|
|||||||
import { DimensionSupplier } from 'app/features/dimensions';
|
import { DimensionSupplier } from 'app/features/dimensions';
|
||||||
import { Feature } from 'ol';
|
import { Feature } from 'ol';
|
||||||
import { Point } from 'ol/geom';
|
import { Point } from 'ol/geom';
|
||||||
import { StyleMaker } from '../style/types';
|
import { StyleMaker, TextStyleConfig } from '../style/types';
|
||||||
import { LocationInfo } from './location';
|
import { LocationInfo } from './location';
|
||||||
|
|
||||||
export interface FeaturesStylesBuilderConfig {
|
export interface FeaturesStylesBuilderConfig {
|
||||||
@ -11,6 +11,7 @@ export interface FeaturesStylesBuilderConfig {
|
|||||||
opacity: number;
|
opacity: number;
|
||||||
styleMaker: StyleMaker;
|
styleMaker: StyleMaker;
|
||||||
textDim?: DimensionSupplier<string>;
|
textDim?: DimensionSupplier<string>;
|
||||||
|
textConfig?: TextStyleConfig;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const getFeatures = (
|
export const getFeatures = (
|
||||||
@ -32,6 +33,9 @@ export const getFeatures = (
|
|||||||
// Get the text for the feature based on text dimension
|
// Get the text for the feature based on text dimension
|
||||||
const text = config?.textDim ? config?.textDim.get(i) : undefined;
|
const text = config?.textDim ? config?.textDim.get(i) : undefined;
|
||||||
|
|
||||||
|
// Get the textConfig
|
||||||
|
const textConfig = config?.textConfig;
|
||||||
|
|
||||||
// Create a new Feature for each point returned from dataFrameToPoints
|
// Create a new Feature for each point returned from dataFrameToPoints
|
||||||
const dot = new Feature(info.points[i]);
|
const dot = new Feature(info.points[i]);
|
||||||
dot.setProperties({
|
dot.setProperties({
|
||||||
@ -39,7 +43,7 @@ export const getFeatures = (
|
|||||||
rowIndex: i,
|
rowIndex: i,
|
||||||
});
|
});
|
||||||
|
|
||||||
dot.setStyle(config.styleMaker({ color, size, text, opacity }));
|
dot.setStyle(config.styleMaker({ color, size, text, opacity, textConfig }));
|
||||||
features.push(dot);
|
features.push(dot);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user