From 9314b8e2fadf78b99ecbcd8588d2507076b42563 Mon Sep 17 00:00:00 2001 From: Nathan Reese Date: Tue, 9 Feb 2021 07:57:00 -0700 Subject: [PATCH] [Maps] use chart pallete registry to support sync colors in dashboard (#88099) * [Maps] use chart pallete registry to support sync colors in dashboard * pass getColor to createLayerInstance * use chartsPaletteServiceGetColor to get categorical color * revert changes to layer_actions * tslint and jest test updates Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> --- x-pack/plugins/maps/kibana.json | 3 +- .../blended_vector_layer.ts | 8 ++++- .../layers/vector_layer/vector_layer.tsx | 15 ++++++-- .../properties/dynamic_color_property.tsx | 35 ++++++++++++++++--- .../classes/styles/vector/vector_style.tsx | 21 +++++++---- .../maps/public/embeddable/map_embeddable.tsx | 28 ++++++++++++++- x-pack/plugins/maps/public/kibana_services.ts | 20 +++++++++++ x-pack/plugins/maps/public/plugin.ts | 2 ++ .../reducers/non_serializable_instances.d.ts | 9 +++++ .../reducers/non_serializable_instances.js | 20 +++++++++++ x-pack/plugins/maps/public/reducers/store.js | 1 + .../public/selectors/map_selectors.test.ts | 5 --- .../maps/public/selectors/map_selectors.ts | 15 +++++--- 13 files changed, 156 insertions(+), 26 deletions(-) diff --git a/x-pack/plugins/maps/kibana.json b/x-pack/plugins/maps/kibana.json index 744cc18c36f3e..3966af9e28742 100644 --- a/x-pack/plugins/maps/kibana.json +++ b/x-pack/plugins/maps/kibana.json @@ -25,7 +25,8 @@ ], "optionalPlugins": [ "home", - "savedObjectsTagging" + "savedObjectsTagging", + "charts" ], "ui": true, "server": true, diff --git a/x-pack/plugins/maps/public/classes/layers/blended_vector_layer/blended_vector_layer.ts b/x-pack/plugins/maps/public/classes/layers/blended_vector_layer/blended_vector_layer.ts index efd022292f90b..5d4b915c4e971 100644 --- a/x-pack/plugins/maps/public/classes/layers/blended_vector_layer/blended_vector_layer.ts +++ b/x-pack/plugins/maps/public/classes/layers/blended_vector_layer/blended_vector_layer.ts @@ -169,6 +169,7 @@ function getClusterStyleDescriptor( } export interface BlendedVectorLayerArguments { + chartsPaletteServiceGetColor?: (value: string) => string | null; source: IVectorSource; layerDescriptor: VectorLayerDescriptor; } @@ -205,7 +206,12 @@ export class BlendedVectorLayer extends VectorLayer implements IVectorLayer { this._documentStyle, this._clusterSource ); - this._clusterStyle = new VectorStyle(clusterStyleDescriptor, this._clusterSource, this); + this._clusterStyle = new VectorStyle( + clusterStyleDescriptor, + this._clusterSource, + this, + options.chartsPaletteServiceGetColor + ); let isClustered = false; const countDataRequest = this.getDataRequest(ACTIVE_COUNT_DATA_ID); diff --git a/x-pack/plugins/maps/public/classes/layers/vector_layer/vector_layer.tsx b/x-pack/plugins/maps/public/classes/layers/vector_layer/vector_layer.tsx index ee1cda6eaee43..e9c0cb29c7c17 100644 --- a/x-pack/plugins/maps/public/classes/layers/vector_layer/vector_layer.tsx +++ b/x-pack/plugins/maps/public/classes/layers/vector_layer/vector_layer.tsx @@ -81,6 +81,7 @@ export interface VectorLayerArguments { source: IVectorSource; joins?: InnerJoin[]; layerDescriptor: VectorLayerDescriptor; + chartsPaletteServiceGetColor?: (value: string) => string | null; } export interface IVectorLayer extends ILayer { @@ -119,13 +120,23 @@ export class VectorLayer extends AbstractLayer { return layerDescriptor as VectorLayerDescriptor; } - constructor({ layerDescriptor, source, joins = [] }: VectorLayerArguments) { + constructor({ + layerDescriptor, + source, + joins = [], + chartsPaletteServiceGetColor, + }: VectorLayerArguments) { super({ layerDescriptor, source, }); this._joins = joins; - this._style = new VectorStyle(layerDescriptor.style, source, this); + this._style = new VectorStyle( + layerDescriptor.style, + source, + this, + chartsPaletteServiceGetColor + ); } getSource(): IVectorSource { diff --git a/x-pack/plugins/maps/public/classes/styles/vector/properties/dynamic_color_property.tsx b/x-pack/plugins/maps/public/classes/styles/vector/properties/dynamic_color_property.tsx index cac56ad1c8a57..d654cdc6bff51 100644 --- a/x-pack/plugins/maps/public/classes/styles/vector/properties/dynamic_color_property.tsx +++ b/x-pack/plugins/maps/public/classes/styles/vector/properties/dynamic_color_property.tsx @@ -16,7 +16,12 @@ import { getPercentilesMbColorRampStops, getColorPalette, } from '../../color_palettes'; -import { COLOR_MAP_TYPE, DATA_MAPPING_FUNCTION } from '../../../../../common/constants'; +import { + COLOR_MAP_TYPE, + DATA_MAPPING_FUNCTION, + FieldFormatter, + VECTOR_STYLES, +} from '../../../../../common/constants'; import { isCategoricalStopsInvalid, getOtherCategoryLabel, @@ -26,6 +31,8 @@ import { Break, BreakedLegend } from '../components/legend/breaked_legend'; import { ColorDynamicOptions, OrdinalColorStop } from '../../../../../common/descriptor_types'; import { LegendProps } from './style_property'; import { getOrdinalSuffix } from '../../../util/ordinal_suffix'; +import { IField } from '../../../fields/field'; +import { IVectorLayer } from '../../../layers/vector_layer/vector_layer'; const UP_TO = i18n.translate('xpack.maps.legend.upto', { defaultMessage: 'up to', @@ -34,6 +41,20 @@ const EMPTY_STOPS = { stops: [], defaultColor: null }; const RGBA_0000 = 'rgba(0,0,0,0)'; export class DynamicColorProperty extends DynamicStyleProperty { + private readonly _chartsPaletteServiceGetColor?: (value: string) => string | null; + + constructor( + options: ColorDynamicOptions, + styleName: VECTOR_STYLES, + field: IField | null, + vectorLayer: IVectorLayer, + getFieldFormatter: (fieldName: string) => null | FieldFormatter, + chartsPaletteServiceGetColor?: (value: string) => string | null + ) { + super(options, styleName, field, vectorLayer, getFieldFormatter); + this._chartsPaletteServiceGetColor = chartsPaletteServiceGetColor; + } + syncCircleColorWithMb(mbLayerId: string, mbMap: MbMap, alpha: number) { const color = this._getMbColor(); mbMap.setPaintProperty(mbLayerId, 'circle-color', color); @@ -260,12 +281,16 @@ export class DynamicColorProperty extends DynamicStyleProperty { - if (stop !== null) { + stops.forEach(({ stop, color }: { stop: string | number | null; color: string | null }) => { + if (stop !== null && color != null) { breaks.push({ color, symbolId, diff --git a/x-pack/plugins/maps/public/classes/styles/vector/vector_style.tsx b/x-pack/plugins/maps/public/classes/styles/vector/vector_style.tsx index cef5f5048e9af..c61e72807224a 100644 --- a/x-pack/plugins/maps/public/classes/styles/vector/vector_style.tsx +++ b/x-pack/plugins/maps/public/classes/styles/vector/vector_style.tsx @@ -178,7 +178,8 @@ export class VectorStyle implements IVectorStyle { constructor( descriptor: VectorStyleDescriptor | null, source: IVectorSource, - layer: IVectorLayer + layer: IVectorLayer, + chartsPaletteServiceGetColor?: (value: string) => string | null ) { this._source = source; this._layer = layer; @@ -197,11 +198,13 @@ export class VectorStyle implements IVectorStyle { ); this._lineColorStyleProperty = this._makeColorProperty( this._descriptor.properties[VECTOR_STYLES.LINE_COLOR], - VECTOR_STYLES.LINE_COLOR + VECTOR_STYLES.LINE_COLOR, + chartsPaletteServiceGetColor ); this._fillColorStyleProperty = this._makeColorProperty( this._descriptor.properties[VECTOR_STYLES.FILL_COLOR], - VECTOR_STYLES.FILL_COLOR + VECTOR_STYLES.FILL_COLOR, + chartsPaletteServiceGetColor ); this._lineWidthStyleProperty = this._makeSizeProperty( this._descriptor.properties[VECTOR_STYLES.LINE_WIDTH], @@ -230,11 +233,13 @@ export class VectorStyle implements IVectorStyle { ); this._labelColorStyleProperty = this._makeColorProperty( this._descriptor.properties[VECTOR_STYLES.LABEL_COLOR], - VECTOR_STYLES.LABEL_COLOR + VECTOR_STYLES.LABEL_COLOR, + chartsPaletteServiceGetColor ); this._labelBorderColorStyleProperty = this._makeColorProperty( this._descriptor.properties[VECTOR_STYLES.LABEL_BORDER_COLOR], - VECTOR_STYLES.LABEL_BORDER_COLOR + VECTOR_STYLES.LABEL_BORDER_COLOR, + chartsPaletteServiceGetColor ); this._labelBorderSizeStyleProperty = new LabelBorderSizeProperty( this._descriptor.properties[VECTOR_STYLES.LABEL_BORDER_SIZE].options, @@ -890,7 +895,8 @@ export class VectorStyle implements IVectorStyle { _makeColorProperty( descriptor: ColorStylePropertyDescriptor | undefined, - styleName: VECTOR_STYLES + styleName: VECTOR_STYLES, + chartsPaletteServiceGetColor?: (value: string) => string | null ) { if (!descriptor || !descriptor.options) { return new StaticColorProperty({ color: '' }, styleName); @@ -904,7 +910,8 @@ export class VectorStyle implements IVectorStyle { styleName, field, this._layer, - this._getFieldFormatter + this._getFieldFormatter, + chartsPaletteServiceGetColor ); } else { throw new Error(`${descriptor} not implemented`); diff --git a/x-pack/plugins/maps/public/embeddable/map_embeddable.tsx b/x-pack/plugins/maps/public/embeddable/map_embeddable.tsx index a1d65bf08c458..b769ac489f565 100644 --- a/x-pack/plugins/maps/public/embeddable/map_embeddable.tsx +++ b/x-pack/plugins/maps/public/embeddable/map_embeddable.tsx @@ -37,6 +37,7 @@ import { import { getIsLayerTOCOpen, getOpenTOCDetails } from '../selectors/ui_selectors'; import { getInspectorAdapters, + setChartsPaletteServiceGetColor, setEventHandlers, EventHandlers, } from '../reducers/non_serializable_instances'; @@ -54,7 +55,12 @@ import { RawValue, } from '../../common/constants'; import { RenderToolTipContent } from '../classes/tooltips/tooltip_property'; -import { getUiActions, getCoreI18n, getHttp } from '../kibana_services'; +import { + getUiActions, + getCoreI18n, + getHttp, + getChartsPaletteServiceGetColor, +} from '../kibana_services'; import { LayerDescriptor } from '../../common/descriptor_types'; import { MapContainer } from '../connected_components/map_container'; import { SavedMap } from '../routes/map_page'; @@ -83,6 +89,7 @@ export class MapEmbeddable private _prevQuery?: Query; private _prevRefreshConfig?: RefreshInterval; private _prevFilters?: Filter[]; + private _prevSyncColors?: boolean; private _prevSearchSessionId?: string; private _domNode?: HTMLElement; private _unsubscribeFromStore?: Unsubscribe; @@ -126,6 +133,8 @@ export class MapEmbeddable } private _initializeStore() { + this._dispatchSetChartsPaletteServiceGetColor(this.input.syncColors); + const store = this._savedMap.getStore(); store.dispatch(setReadOnly(true)); store.dispatch(disableScrollZoom()); @@ -221,6 +230,10 @@ export class MapEmbeddable if (this.input.refreshConfig && !_.isEqual(this.input.refreshConfig, this._prevRefreshConfig)) { this._dispatchSetRefreshConfig(this.input.refreshConfig); } + + if (this.input.syncColors !== this._prevSyncColors) { + this._dispatchSetChartsPaletteServiceGetColor(this.input.syncColors); + } } _dispatchSetQuery({ @@ -261,6 +274,19 @@ export class MapEmbeddable ); } + async _dispatchSetChartsPaletteServiceGetColor(syncColors?: boolean) { + this._prevSyncColors = syncColors; + const chartsPaletteServiceGetColor = syncColors + ? await getChartsPaletteServiceGetColor() + : null; + if (syncColors !== this._prevSyncColors) { + return; + } + this._savedMap + .getStore() + .dispatch(setChartsPaletteServiceGetColor(chartsPaletteServiceGetColor)); + } + /** * * @param {HTMLElement} domNode diff --git a/x-pack/plugins/maps/public/kibana_services.ts b/x-pack/plugins/maps/public/kibana_services.ts index 632a5f5382f73..4a7bccb31380d 100644 --- a/x-pack/plugins/maps/public/kibana_services.ts +++ b/x-pack/plugins/maps/public/kibana_services.ts @@ -11,6 +11,7 @@ import { MapsLegacyConfig } from '../../../../src/plugins/maps_legacy/config'; import { MapsConfigType } from '../config'; import { MapsPluginStartDependencies } from './plugin'; import { EMSSettings } from '../common/ems_settings'; +import { PaletteRegistry } from '../../../../src/plugins/charts/public'; let kibanaVersion: string; export const setKibanaVersion = (version: string) => (kibanaVersion = version); @@ -83,3 +84,22 @@ export const getShareService = () => pluginsStart.share; export const getIsAllowByValueEmbeddables = () => pluginsStart.dashboard.dashboardFeatureFlagConfig.allowByValueEmbeddables; + +export async function getChartsPaletteServiceGetColor(): Promise< + ((value: string) => string) | null +> { + const paletteRegistry: PaletteRegistry | null = pluginsStart.charts + ? await pluginsStart.charts.palettes.getPalettes() + : null; + if (!paletteRegistry) { + return null; + } + + const paletteDefinition = paletteRegistry.get('default'); + const chartConfiguration = { syncColors: true }; + return (value: string) => { + const series = [{ name: value, rankAtDepth: 0, totalSeriesAtDepth: 1 }]; + const color = paletteDefinition.getColor(series, chartConfiguration); + return color ? color : '#3d3d3d'; + }; +} diff --git a/x-pack/plugins/maps/public/plugin.ts b/x-pack/plugins/maps/public/plugin.ts index 8889d1d44f10f..4c668e0a2276b 100644 --- a/x-pack/plugins/maps/public/plugin.ts +++ b/x-pack/plugins/maps/public/plugin.ts @@ -64,6 +64,7 @@ import { } from './licensed_features'; import { EMSSettings } from '../common/ems_settings'; import { SavedObjectTaggingPluginStart } from '../../saved_objects_tagging/public'; +import { ChartsPluginStart } from '../../../../src/plugins/charts/public'; export interface MapsPluginSetupDependencies { inspector: InspectorSetupContract; @@ -76,6 +77,7 @@ export interface MapsPluginSetupDependencies { } export interface MapsPluginStartDependencies { + charts: ChartsPluginStart; data: DataPublicPluginStart; embeddable: EmbeddableStart; mapsFileUpload: FileUploadStartContract; diff --git a/x-pack/plugins/maps/public/reducers/non_serializable_instances.d.ts b/x-pack/plugins/maps/public/reducers/non_serializable_instances.d.ts index 54a90946a5a89..9808a5e09b8ab 100644 --- a/x-pack/plugins/maps/public/reducers/non_serializable_instances.d.ts +++ b/x-pack/plugins/maps/public/reducers/non_serializable_instances.d.ts @@ -15,6 +15,7 @@ export type NonSerializableState = { inspectorAdapters: Adapters; cancelRequestCallbacks: Map {}>; // key is request token, value is cancel callback eventHandlers: Partial; + chartsPaletteServiceGetColor: (value: string) => string | null; }; export interface ResultMeta { @@ -58,6 +59,14 @@ export function getInspectorAdapters(state: MapStoreState): Adapters; export function getEventHandlers(state: MapStoreState): Partial; +export function getChartsPaletteServiceGetColor( + state: MapStoreState +): (value: string) => string | null; + +export function setChartsPaletteServiceGetColor( + chartsPaletteServiceGetColor: ((value: string) => string) | null +): AnyAction; + export function cancelRequest(requestToken?: symbol): AnyAction; export function registerCancelCallback(requestToken: symbol, callback: () => void): AnyAction; diff --git a/x-pack/plugins/maps/public/reducers/non_serializable_instances.js b/x-pack/plugins/maps/public/reducers/non_serializable_instances.js index 46846a8df3f23..4cc4e91a308a5 100644 --- a/x-pack/plugins/maps/public/reducers/non_serializable_instances.js +++ b/x-pack/plugins/maps/public/reducers/non_serializable_instances.js @@ -12,6 +12,7 @@ import { getShowMapsInspectorAdapter } from '../kibana_services'; const REGISTER_CANCEL_CALLBACK = 'REGISTER_CANCEL_CALLBACK'; const UNREGISTER_CANCEL_CALLBACK = 'UNREGISTER_CANCEL_CALLBACK'; const SET_EVENT_HANDLERS = 'SET_EVENT_HANDLERS'; +const SET_CHARTS_PALETTE_SERVICE_GET_COLOR = 'SET_CHARTS_PALETTE_SERVICE_GET_COLOR'; function createInspectorAdapters() { const inspectorAdapters = { @@ -30,6 +31,7 @@ export function nonSerializableInstances(state, action = {}) { inspectorAdapters: createInspectorAdapters(), cancelRequestCallbacks: new Map(), // key is request token, value is cancel callback eventHandlers: {}, + chartsPaletteServiceGetColor: null, }; } @@ -50,6 +52,12 @@ export function nonSerializableInstances(state, action = {}) { eventHandlers: action.eventHandlers, }; } + case SET_CHARTS_PALETTE_SERVICE_GET_COLOR: { + return { + ...state, + chartsPaletteServiceGetColor: action.chartsPaletteServiceGetColor, + }; + } default: return state; } @@ -68,6 +76,11 @@ export const getEventHandlers = ({ nonSerializableInstances }) => { return nonSerializableInstances.eventHandlers; }; +export function getChartsPaletteServiceGetColor({ nonSerializableInstances }) { + console.log('getChartsPaletteServiceGetColor', nonSerializableInstances); + return nonSerializableInstances.chartsPaletteServiceGetColor; +} + // Actions export const registerCancelCallback = (requestToken, callback) => { return { @@ -104,3 +117,10 @@ export const setEventHandlers = (eventHandlers = {}) => { eventHandlers, }; }; + +export function setChartsPaletteServiceGetColor(chartsPaletteServiceGetColor) { + return { + type: SET_CHARTS_PALETTE_SERVICE_GET_COLOR, + chartsPaletteServiceGetColor, + }; +} diff --git a/x-pack/plugins/maps/public/reducers/store.js b/x-pack/plugins/maps/public/reducers/store.js index 3c9b5d1b98e29..4e355add59fee 100644 --- a/x-pack/plugins/maps/public/reducers/store.js +++ b/x-pack/plugins/maps/public/reducers/store.js @@ -15,6 +15,7 @@ import { MAP_DESTROYED } from '../actions'; export const DEFAULT_MAP_STORE_STATE = { ui: { ...DEFAULT_MAP_UI_STATE }, map: { ...DEFAULT_MAP_STATE }, + nonSerializableInstances: {}, }; export function createMapStore() { diff --git a/x-pack/plugins/maps/public/selectors/map_selectors.test.ts b/x-pack/plugins/maps/public/selectors/map_selectors.test.ts index eb11ee61d9deb..dd6a9fc377e5b 100644 --- a/x-pack/plugins/maps/public/selectors/map_selectors.test.ts +++ b/x-pack/plugins/maps/public/selectors/map_selectors.test.ts @@ -11,11 +11,6 @@ jest.mock('../classes/layers/blended_vector_layer/blended_vector_layer', () => { jest.mock('../classes/layers/heatmap_layer/heatmap_layer', () => {}); jest.mock('../classes/layers/vector_tile_layer/vector_tile_layer', () => {}); jest.mock('../classes/joins/inner_join', () => {}); -jest.mock('../reducers/non_serializable_instances', () => ({ - getInspectorAdapters: () => { - return {}; - }, -})); jest.mock('../kibana_services', () => ({ getTimeFilter: () => ({ getTime: () => { diff --git a/x-pack/plugins/maps/public/selectors/map_selectors.ts b/x-pack/plugins/maps/public/selectors/map_selectors.ts index 34af789f6834f..27281fe17f0fa 100644 --- a/x-pack/plugins/maps/public/selectors/map_selectors.ts +++ b/x-pack/plugins/maps/public/selectors/map_selectors.ts @@ -18,7 +18,10 @@ import { VectorStyle } from '../classes/styles/vector/vector_style'; import { HeatmapLayer } from '../classes/layers/heatmap_layer/heatmap_layer'; import { BlendedVectorLayer } from '../classes/layers/blended_vector_layer/blended_vector_layer'; import { getTimeFilter } from '../kibana_services'; -import { getInspectorAdapters } from '../reducers/non_serializable_instances'; +import { + getChartsPaletteServiceGetColor, + getInspectorAdapters, +} from '../reducers/non_serializable_instances'; import { TiledVectorLayer } from '../classes/layers/tiled_vector_layer/tiled_vector_layer'; import { copyPersistentState, TRACKED_LAYER_DESCRIPTOR } from '../reducers/util'; import { InnerJoin } from '../classes/joins/inner_join'; @@ -55,7 +58,8 @@ import { ILayer } from '../classes/layers/layer'; export function createLayerInstance( layerDescriptor: LayerDescriptor, - inspectorAdapters?: Adapters + inspectorAdapters?: Adapters, + chartsPaletteServiceGetColor?: (value: string) => string | null ): ILayer { const source: ISource = createSourceInstance(layerDescriptor.sourceDescriptor, inspectorAdapters); @@ -75,6 +79,7 @@ export function createLayerInstance( layerDescriptor: vectorLayerDescriptor, source: source as IVectorSource, joins, + chartsPaletteServiceGetColor, }); case VectorTileLayer.type: return new VectorTileLayer({ layerDescriptor, source: source as ITMSSource }); @@ -84,6 +89,7 @@ export function createLayerInstance( return new BlendedVectorLayer({ layerDescriptor: layerDescriptor as VectorLayerDescriptor, source: source as IVectorSource, + chartsPaletteServiceGetColor, }); case TiledVectorLayer.type: return new TiledVectorLayer({ @@ -295,9 +301,10 @@ export const getSpatialFiltersLayer = createSelector( export const getLayerList = createSelector( getLayerListRaw, getInspectorAdapters, - (layerDescriptorList, inspectorAdapters) => { + getChartsPaletteServiceGetColor, + (layerDescriptorList, inspectorAdapters, chartsPaletteServiceGetColor) => { return layerDescriptorList.map((layerDescriptor) => - createLayerInstance(layerDescriptor, inspectorAdapters) + createLayerInstance(layerDescriptor, inspectorAdapters, chartsPaletteServiceGetColor) ); } );