Skip to content

Commit

Permalink
simplifications of MappedColors
Browse files Browse the repository at this point in the history
  • Loading branch information
mbondyra committed Nov 12, 2024
1 parent 3f9a454 commit e02560d
Show file tree
Hide file tree
Showing 2 changed files with 18 additions and 95 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -11,66 +11,30 @@ import _ from 'lodash';
import { MappedColors } from './mapped_colors';

describe('Mapped Colors', () => {
const mappedColors = new MappedColors();

beforeEach(() => {
mappedColors.purge();
});

it('should properly map keys to unique colors', () => {
const mappedColors = new MappedColors();
const arr = [1, 2, 3, 4, 5];
mappedColors.mapKeys(arr);
expect(_(mappedColors.mapping).values().uniq().size()).toBe(arr.length);
});

it('should have a flush method that moves the current map to the old map', function () {
const arr = [1, 2, 3, 4, 5];
mappedColors.mapKeys(arr);
expect(_.keys(mappedColors.mapping).length).toBe(5);
expect(_.keys(mappedColors.oldMap).length).toBe(0);

mappedColors.flush();

expect(_.keys(mappedColors.oldMap).length).toBe(5);
expect(_.keys(mappedColors.mapping).length).toBe(0);

mappedColors.flush();

expect(_.keys(mappedColors.oldMap).length).toBe(0);
expect(_.keys(mappedColors.mapping).length).toBe(0);
});

it('should use colors in the oldMap if they are available', function () {
const arr = [1, 2, 3, 4, 5];
mappedColors.mapKeys(arr);
expect(_(mappedColors.mapping).values().uniq().size()).toBe(arr.length);
expect(_.keys(mappedColors.mapping).length).toBe(5);
expect(_.keys(mappedColors.oldMap).length).toBe(0);

mappedColors.flush();

mappedColors.mapKeys([3, 4, 5]);
expect(_.keys(mappedColors.oldMap).length).toBe(5);
expect(_.keys(mappedColors.mapping).length).toBe(3);

expect(mappedColors.mapping[1]).toBe(undefined);
expect(mappedColors.mapping[2]).toBe(undefined);
expect(mappedColors.mapping[3]).toEqual(mappedColors.oldMap[3]);
expect(mappedColors.mapping[4]).toEqual(mappedColors.oldMap[4]);
expect(mappedColors.mapping[5]).toEqual(mappedColors.oldMap[5]);
});

it('should have a purge method that clears both maps', function () {
it('should allow to map keys multiple times and add new colors when doing so', function () {
const mappedColors = new MappedColors();
const arr = [1, 2, 3, 4, 5];
mappedColors.mapKeys(arr);
mappedColors.flush();
mappedColors.mapKeys(arr);

expect(_.keys(mappedColors.mapping).length).toBe(5);
expect(_.keys(mappedColors.oldMap).length).toBe(5);

mappedColors.purge();

expect(_.keys(mappedColors.mapping).length).toBe(0);
expect(_.keys(mappedColors.oldMap).length).toBe(0);
mappedColors.mapKeys([6, 7]);

expect(_.keys(mappedColors.mapping).length).toBe(7);
expect(mappedColors.mapping).toEqual({
'1': '#00a69b',
'2': '#57c17b',
'3': '#6f87d8',
'4': '#663db8',
'5': '#bc52bc',
'6': '#9e3533',
'7': '#daa05d',
});
});
});
45 changes: 2 additions & 43 deletions src/plugins/charts/public/services/mapped_colors/mapped_colors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,78 +8,37 @@
*/

import _ from 'lodash';
import Color from 'color';

import { createColorPalette } from '../../static/colors';

const standardizeColor = (color: string) => new Color(color).hex().toLowerCase();

/**
* Maintains a lookup table that associates the value (key) with a hex color (value)
* across the visualizations.
* Provides functions to interact with the lookup table
*/
export class MappedColors {
private _oldMap: any;
private _mapping: any;

constructor(private colorPaletteFn: (num: number) => string[] = createColorPalette) {
this._oldMap = {};
this._mapping = {};
}

private getConfigColorMapping(): Record<string, string> {
return _.mapValues({}, standardizeColor);
}

public get oldMap(): any {
return this._oldMap;
}

public get mapping(): any {
return this._mapping;
}

get(key: string | number) {
return this.getConfigColorMapping()[key as any] || this._mapping[key];
}

getColorFromConfig(key: string | number) {
return this.getConfigColorMapping()[key as any];
}

flush() {
this._oldMap = _.clone(this._mapping);
this._mapping = {};
}

purge() {
this._oldMap = {};
this._mapping = {};
return this._mapping[key];
}

mapKeys(keys: Array<string | number>) {
const configMapping = this.getConfigColorMapping();
const configColors = _.values(configMapping);
const oldColors = _.values(this._oldMap);

const keysToMap: Array<string | number> = [];
_.each(keys, (key) => {
// If this key is mapped in the config, it's unnecessary to have it mapped here
if (configMapping[key as any]) delete this._mapping[key];

// If this key is mapped to a color used by the config color mapping, we need to remap it
if (_.includes(configColors, this._mapping[key])) keysToMap.push(key);

// if key exist in oldMap, move it to mapping
if (this._oldMap[key]) this._mapping[key] = this._oldMap[key];

// If this key isn't mapped, we need to map it
if (this.get(key) == null) keysToMap.push(key);
});

// Generate a color palette big enough that all new keys can have unique color values
const allColors = _(this._mapping).values().union(configColors).union(oldColors).value();
const allColors = _(this._mapping).values().value();
const colorPalette = this.colorPaletteFn(allColors.length + keysToMap.length);
let newColors = _.difference(colorPalette, allColors);

Expand Down

0 comments on commit e02560d

Please sign in to comment.