diff --git a/CHANGELOG.md b/CHANGELOG.md index aeb8d55ee5cc..9b2abc718b76 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -58,6 +58,7 @@ Inspired from [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) - [Table Visualization] Remove custom styling for text-align:center in favor of OUI utility class. ([#4164](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/4164)) - Replace the use of `bluebird` in `saved_objects` plugin ([#4026](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/4026)) - [Vis Colors] Update default color in TSVB to use `ouiPaletteColorBlind()[0]`([#4363](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/4363)) +- [Vis Colors] Update legacy seed colors to use `ouiPaletteColorBlind()` ([#4348](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/4348)) ### 🔩 Tests diff --git a/src/plugins/charts/public/services/colors/color_palette.ts b/src/plugins/charts/public/services/colors/color_palette.ts index ac59a3c85f0d..646dcf115921 100644 --- a/src/plugins/charts/public/services/colors/color_palette.ts +++ b/src/plugins/charts/public/services/colors/color_palette.ts @@ -29,48 +29,17 @@ */ import _ from 'lodash'; -import { hsl } from 'color'; -import { seedColors } from './seed_colors'; - -const offset = 300; // Hue offset to start at - -const fraction = function (goal: number) { - const walkTree = (numerator: number, denominator: number, bytes: number[]): number => { - if (bytes.length) { - return walkTree(numerator * 2 + (bytes.pop() ? 1 : -1), denominator * 2, bytes); - } else { - return numerator / denominator; - } - }; - - const b = (goal + 2) - .toString(2) - .split('') - .map(function (num) { - return parseInt(num, 10); - }); - b.shift(); - - return walkTree(1, 2, b); -}; +import { euiPaletteColorBlind } from '@elastic/eui'; /** - * Generates an array of hex colors the length of the input number. - * If the number is greater than the length of seed colors available, - * new colors are generated up to the value of the input number. + * Generates an array of hex colors the length of the input number or little + * greater than the input number. */ export function createColorPalette(num: number): string[] { if (!_.isNumber(num)) { throw new TypeError('ColorPaletteUtilService expects a number'); } - const colors = seedColors; - const seedLength = seedColors.length; - - _.times(num - seedLength, function (i) { - colors.push(hsl((fraction(i + seedLength + 1) * 360 + offset) % 360, 50, 50).hex()); - }); - - return colors; + return euiPaletteColorBlind({ rotations: Math.ceil(num / 10), direction: 'both' }); } diff --git a/src/plugins/charts/public/services/colors/colors.test.ts b/src/plugins/charts/public/services/colors/colors.test.ts index f25a1d7c476d..c189b9dc7bae 100644 --- a/src/plugins/charts/public/services/colors/colors.test.ts +++ b/src/plugins/charts/public/services/colors/colors.test.ts @@ -30,7 +30,7 @@ import { coreMock } from '../../../../../core/public/mocks'; import { COLOR_MAPPING_SETTING } from '../../../common'; -import { seedColors } from './seed_colors'; +import { euiPaletteColorBlind } from '@elastic/eui'; import { ColorsService } from './colors'; // Local state for config @@ -138,7 +138,7 @@ describe('Vislib Color Service', () => { }); it('should return the first hex color in the seed colors array', () => { - expect(color(arr[0])).toBe(seedColors[0]); + expect(color(arr[0])).toBe(euiPaletteColorBlind()[0]); }); it('should return the value from the mapped colors', () => { diff --git a/src/plugins/charts/public/services/colors/colors.ts b/src/plugins/charts/public/services/colors/colors.ts index 8f60e3bc29f1..1706f67acf97 100644 --- a/src/plugins/charts/public/services/colors/colors.ts +++ b/src/plugins/charts/public/services/colors/colors.ts @@ -32,8 +32,8 @@ import _ from 'lodash'; import { CoreSetup } from 'opensearch-dashboards/public'; +import { euiPaletteColorBlind } from '@elastic/eui'; import { MappedColors } from './mapped_colors'; -import { seedColors } from './seed_colors'; /** * Accepts an array of strings or numbers that are used to create a @@ -44,7 +44,7 @@ import { seedColors } from './seed_colors'; export class ColorsService { private _mappedColors?: MappedColors; - public readonly seedColors = seedColors; + public readonly seedColors = euiPaletteColorBlind(); public get mappedColors() { if (!this._mappedColors) { diff --git a/src/plugins/charts/public/services/colors/colors_palette.test.ts b/src/plugins/charts/public/services/colors/colors_palette.test.ts index ca9d2f2654e1..08cb9c4194a0 100644 --- a/src/plugins/charts/public/services/colors/colors_palette.test.ts +++ b/src/plugins/charts/public/services/colors/colors_palette.test.ts @@ -28,8 +28,8 @@ * under the License. */ -import { seedColors } from './seed_colors'; import { createColorPalette } from './color_palette'; +import { euiPaletteColorBlind } from '@elastic/eui'; describe('Color Palette', () => { const num1 = 45; @@ -46,6 +46,12 @@ describe('Color Palette', () => { colorPalette = createColorPalette(num1); }); + function isHexValue(value: string): boolean { + // Check if the hex value is valid. + const regex = /^#[0-9a-fA-F]{3}|[0-9a-fA-F]{6}$/; + return regex.test(value) ? true : false; + } + it('should throw an error if input is not a number', () => { expect(() => { // @ts-expect-error @@ -86,12 +92,13 @@ describe('Color Palette', () => { expect(colorPalette).toBeInstanceOf(Array); }); - it('should return an array of the same length as the input', () => { - expect(colorPalette.length).toBe(num1); + it('should return an array of the same length as the input or greater than the input', () => { + expect(colorPalette.length).toBeGreaterThan(num1); }); it('should return the seed color array when input length is 72', () => { - expect(createColorPalette(num2)[71]).toBe(seedColors[71]); + expect(createColorPalette(num2).length).toBe(80); + expect(isHexValue(createColorPalette(num2)[71])).toBe(true); }); it('should return an array of the same length as the input when input is greater than 72', () => { @@ -99,10 +106,12 @@ describe('Color Palette', () => { }); it('should create new darker colors when input is greater than 72', () => { - expect(createColorPalette(num3)[72]).not.toEqual(seedColors[0]); + expect(createColorPalette(num3)[72]).not.toEqual(euiPaletteColorBlind()[0]); }); it('should create new colors and convert them correctly', () => { - expect(createColorPalette(num3)[72]).toEqual('#404ABF'); + expect(createColorPalette(num3).length).toBe(num3); + expect(createColorPalette(num3)[72]).not.toEqual(euiPaletteColorBlind()[9]); + expect(isHexValue(createColorPalette(num3)[89])).toBe(true); }); }); diff --git a/src/plugins/charts/public/services/colors/mapped_colors.test.ts b/src/plugins/charts/public/services/colors/mapped_colors.test.ts index 3db2db01dcbd..2753b37e56dc 100644 --- a/src/plugins/charts/public/services/colors/mapped_colors.test.ts +++ b/src/plugins/charts/public/services/colors/mapped_colors.test.ts @@ -33,7 +33,7 @@ import Color from 'color'; import { coreMock } from '../../../../../core/public/mocks'; import { COLOR_MAPPING_SETTING } from '../../../common'; -import { seedColors } from './seed_colors'; +import { euiPaletteColorBlind } from '@elastic/eui'; import { MappedColors } from './mapped_colors'; // Local state for config @@ -65,19 +65,19 @@ describe('Mapped Colors', () => { }); it('should not include colors used by the config', () => { - const newConfig = { bar: seedColors[0] }; + const newConfig = { bar: euiPaletteColorBlind()[9] }; config.set(COLOR_MAPPING_SETTING, newConfig); const arr = ['foo', 'baz', 'qux']; mappedColors.mapKeys(arr); const colorValues = _(mappedColors.mapping).values(); - expect(colorValues).not.toContain(seedColors[0]); + expect(colorValues).not.toContain(euiPaletteColorBlind()[9]); expect(colorValues.uniq().size()).toBe(arr.length); }); it('should create a unique array of colors even when config is set', () => { - const newConfig = { bar: seedColors[0] }; + const newConfig = { bar: euiPaletteColorBlind()[9] }; config.set(COLOR_MAPPING_SETTING, newConfig); const arr = ['foo', 'bar', 'baz', 'qux']; @@ -85,11 +85,11 @@ describe('Mapped Colors', () => { const expectedSize = _(arr).difference(_.keys(newConfig)).size(); expect(_(mappedColors.mapping).values().uniq().size()).toBe(expectedSize); - expect(mappedColors.get(arr[0])).not.toBe(seedColors[0]); + expect(mappedColors.get(arr[0])).not.toBe(euiPaletteColorBlind()[9]); }); it('should treat different formats of colors as equal', () => { - const color = new Color(seedColors[0]); + const color = new Color(euiPaletteColorBlind()[9]); const rgb = `rgb(${color.red()}, ${color.green()}, ${color.blue()})`; const newConfig = { bar: rgb }; config.set(COLOR_MAPPING_SETTING, newConfig); @@ -99,8 +99,8 @@ describe('Mapped Colors', () => { const expectedSize = _(arr).difference(_.keys(newConfig)).size(); expect(_(mappedColors.mapping).values().uniq().size()).toBe(expectedSize); - expect(mappedColors.get(arr[0])).not.toBe(seedColors[0]); - expect(mappedColors.get('bar')).toBe(seedColors[0]); + expect(mappedColors.get(arr[0])).not.toBe(euiPaletteColorBlind()[9]); + expect(mappedColors.get('bar')).toBe(euiPaletteColorBlind()[9].toLowerCase()); }); it('should have a flush method that moves the current map to the old map', function () { diff --git a/src/plugins/charts/public/services/colors/seed_colors.test.ts b/src/plugins/charts/public/services/colors/seed_colors.test.ts deleted file mode 100644 index ef13065554e4..000000000000 --- a/src/plugins/charts/public/services/colors/seed_colors.test.ts +++ /dev/null @@ -1,37 +0,0 @@ -/* - * SPDX-License-Identifier: Apache-2.0 - * - * The OpenSearch Contributors require contributions made to - * this file be licensed under the Apache-2.0 license or a - * compatible open source license. - * - * Any modifications Copyright OpenSearch Contributors. See - * GitHub history for details. - */ - -/* - * Licensed to Elasticsearch B.V. under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch B.V. licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import { seedColors } from './seed_colors'; - -describe('Seed Colors', function () { - it('should return an array', function () { - expect(seedColors).toBeInstanceOf(Array); - }); -}); diff --git a/src/plugins/charts/public/services/colors/seed_colors.ts b/src/plugins/charts/public/services/colors/seed_colors.ts deleted file mode 100644 index c7527f7768b1..000000000000 --- a/src/plugins/charts/public/services/colors/seed_colors.ts +++ /dev/null @@ -1,44 +0,0 @@ -/* - * SPDX-License-Identifier: Apache-2.0 - * - * The OpenSearch Contributors require contributions made to - * this file be licensed under the Apache-2.0 license or a - * compatible open source license. - * - * Any modifications Copyright OpenSearch Contributors. See - * GitHub history for details. - */ - -/* - * Licensed to Elasticsearch B.V. under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch B.V. licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -/** - * Using a random color generator presented awful colors and unpredictable color schemes. - * So we needed to come up with a color scheme of our own that creates consistent, pleasing color patterns. - * The order allows us to guarantee that 1st, 2nd, 3rd, etc values always get the same color. - */ -export const seedColors: string[] = [ - '#00a69b', - '#57c17b', - '#6f87d8', - '#663db8', - '#bc52bc', - '#9e3533', - '#daa05d', -]; diff --git a/test/functional/apps/dashboard/dashboard_state.js b/test/functional/apps/dashboard/dashboard_state.js index d4ca87821204..924f4c478855 100644 --- a/test/functional/apps/dashboard/dashboard_state.js +++ b/test/functional/apps/dashboard/dashboard_state.js @@ -34,6 +34,8 @@ import { PIE_CHART_VIS_NAME, AREA_CHART_VIS_NAME } from '../../page_objects/dash import { DEFAULT_PANEL_WIDTH } from '../../../../src/plugins/dashboard/public/application/embeddable/dashboard_constants'; +import { euiPaletteColorBlind } from '@elastic/eui'; + export default function ({ getService, getPageObjects }) { const PageObjects = getPageObjects([ 'dashboard', @@ -278,13 +280,15 @@ export default function ({ getService, getPageObjects }) { await retry.try(async () => { const pieSliceStyle = await pieChart.getPieSliceStyle('80,000'); // The default green color that was stored with the visualization before any dashboard overrides. - expect(pieSliceStyle.indexOf('rgb(87, 193, 123)')).to.be.greaterThan(0); + expect(pieSliceStyle.indexOf(euiPaletteColorBlind()[1])).to.be.greaterThan(0); }); }); it('resets the legend color as well', async function () { await retry.try(async () => { - const colorExists = await PageObjects.visChart.doesSelectedLegendColorExist('#57c17b'); + const colorExists = await PageObjects.visChart.doesSelectedLegendColorExist( + euiPaletteColorBlind()[1] + ); expect(colorExists).to.be(true); }); });