diff --git a/src/components/core/base/BaseChart.tsx b/src/components/core/base/BaseChart.tsx index 600efb733a..2d7fe63247 100644 --- a/src/components/core/base/BaseChart.tsx +++ b/src/components/core/base/BaseChart.tsx @@ -22,6 +22,7 @@ import { import { ChartPropTypes, Requireable } from '../../../proptypes/Chart'; import { BaseVisualization } from './BaseVisualization'; import { OnLegendReady } from '../../../interfaces/Events'; +import { getValidColorPalette } from '../../visualizations/utils/color'; export { Requireable }; export interface ICommonChartProps extends ICommonVisualizationProps { @@ -61,7 +62,9 @@ export class StatelessBaseChart extends BaseVisualization diff --git a/src/components/visualizations/chart/Chart.tsx b/src/components/visualizations/chart/Chart.tsx index b5b3a7866f..d9b7200e0f 100644 --- a/src/components/visualizations/chart/Chart.tsx +++ b/src/components/visualizations/chart/Chart.tsx @@ -41,6 +41,7 @@ export interface IChartLimits { export interface IChartConfig { colors?: string[]; + colorPalette?: IColorPalette; type?: VisType; legend?: ILegendConfig; legendLayout?: string; @@ -73,6 +74,20 @@ export interface IChartProps { callback(): void; } +export interface IColorPaletteItem { + guid: string; + fill: { + r: number; + g: number; + b: number; + }; +} + +export interface IColorPalette { + [index: number]: IColorPaletteItem; + length: number; +} + export default class Chart extends React.Component { public static defaultProps: Partial = { callback: noop, diff --git a/src/components/visualizations/chart/chartOptionsBuilder.ts b/src/components/visualizations/chart/chartOptionsBuilder.ts index e645915d57..0ffb5c3c40 100644 --- a/src/components/visualizations/chart/chartOptionsBuilder.ts +++ b/src/components/visualizations/chart/chartOptionsBuilder.ts @@ -1383,7 +1383,7 @@ export function getChartOptions( invariant(measureGroup, 'missing measureGroup'); const colorStrategy = ColorFactory.getColorStrategy( - config.colors, + config.colorPalette, measureGroup, viewByAttribute, stackByAttribute, diff --git a/src/components/visualizations/chart/colorFactory.ts b/src/components/visualizations/chart/colorFactory.ts index 43e815bdee..9a0e069ab7 100644 --- a/src/components/visualizations/chart/colorFactory.ts +++ b/src/components/visualizations/chart/colorFactory.ts @@ -6,7 +6,8 @@ import { DEFAULT_COLOR_PALETTE, HEATMAP_BLUE_COLOR_PALETTE, getLighterColor, - normalizeColorToRGB + normalizeColorToRGB, + getRgbString } from '../utils/color'; import { @@ -21,12 +22,12 @@ import { isDerivedMeasure, findParentMeasureIndex } from './chartOptionsBuilder'; +import { IColorPalette } from './Chart'; export interface IColorStrategy { getColorByIndex(index: number): string; } export type HighChartColorPalette = string[]; -export type ColorPalette = string[]; export type MeasureGroupType = Execution.IMeasureGroupHeader['measureGroupHeader']; export const attributeChartSupportedTypes = [ VisualizationTypes.PIE, @@ -39,7 +40,7 @@ export const attributeChartSupportedTypes = [ export abstract class ColorStrategy implements IColorStrategy { protected palette: HighChartColorPalette; constructor( - colorPalette: ColorPalette, + colorPalette: IColorPalette, measureGroup: MeasureGroupType, viewByAttribute: any, stackByAttribute: any, @@ -58,17 +59,18 @@ export abstract class ColorStrategy implements IColorStrategy { } protected abstract createPalette( - colorPalette: ColorPalette, + colorPalette: IColorPalette, measureGroup: MeasureGroupType, viewByAttribute: any, stackByAttribute: any, afm: AFM.IAfm ): HighChartColorPalette; } +const emptyColorPaletteItem = { guid: 'none', fill: { r: 0, g: 0, b: 0 } }; export class MeasureColorStrategy extends ColorStrategy { protected createPalette( - colorPalette: ColorPalette, + colorPalette: IColorPalette, measureGroup: MeasureGroupType, _viewByAttribute: any, _stackByAttribute: any, @@ -78,7 +80,7 @@ export class MeasureColorStrategy extends ColorStrategy { const paletteMeasures = range(measureGroup.items.length).map((measureItemIndex) => { if (isDerivedMeasure(measureGroup.items[measureItemIndex], afm)) { - return ''; + return emptyColorPaletteItem; } const colorIndex = parentMeasuresCounter % colorPalette.length; parentMeasuresCounter++; @@ -87,29 +89,28 @@ export class MeasureColorStrategy extends ColorStrategy { return paletteMeasures.map((color, measureItemIndex) => { if (!isDerivedMeasure(measureGroup.items[measureItemIndex], afm)) { - return color; + return getRgbString(color); } const parentMeasureIndex = findParentMeasureIndex(afm, measureItemIndex); if (parentMeasureIndex > -1) { const sourceMeasureColor = paletteMeasures[parentMeasureIndex]; - return getLighterColor(normalizeColorToRGB(sourceMeasureColor), 0.6); + return getLighterColor(normalizeColorToRGB(getRgbString(sourceMeasureColor)), 0.6); } - return color; - + return getRgbString(color); }); } } export class AttributeColorStrategy extends ColorStrategy { protected createPalette( - colorPalette: ColorPalette, + colorPalette: IColorPalette, _measureGroup: MeasureGroupType, viewByAttribute: any, stackByAttribute: any, _afm: AFM.IAfm ): HighChartColorPalette { const itemsCount = stackByAttribute ? stackByAttribute.items.length : viewByAttribute.items.length; - return range(itemsCount).map(itemIndex => colorPalette[itemIndex % colorPalette.length]); + return range(itemsCount).map(itemIndex => getRgbString(colorPalette[itemIndex % colorPalette.length])); } } @@ -119,7 +120,7 @@ export class HeatMapColorStrategy extends ColorStrategy { } protected createPalette( - _colorPalette: ColorPalette, + _colorPalette: IColorPalette, _measureGroup: MeasureGroupType, _viewByAttribute: any, _stackByAttribute: any, @@ -131,7 +132,7 @@ export class HeatMapColorStrategy extends ColorStrategy { export class TreeMapColorStrategy extends MeasureColorStrategy { protected createPalette( - colorPalette: ColorPalette, + colorPalette: IColorPalette, measureGroup: MeasureGroupType, viewByAttribute: any, stackByAttribute: any, @@ -139,7 +140,7 @@ export class TreeMapColorStrategy extends MeasureColorStrategy { ): HighChartColorPalette { if (viewByAttribute) { const itemsCount = viewByAttribute.items.length; - return range(itemsCount).map(itemIndex => colorPalette[itemIndex % colorPalette.length]); + return range(itemsCount).map(itemIndex => getRgbString(colorPalette[itemIndex % colorPalette.length])); } return super.createPalette( colorPalette, @@ -158,7 +159,7 @@ export function isAttributeColorPalette(type: string, afm: AFM.IAfm, stackByAttr export class ColorFactory { public static getColorStrategy( - colorPalette: ColorPalette = DEFAULT_COLOR_PALETTE, + colorPalette: IColorPalette = DEFAULT_COLOR_PALETTE, measureGroup: MeasureGroupType, viewByAttribute: any, stackByAttribute: any, diff --git a/src/components/visualizations/chart/highcharts/plugins/test/dataLabelsColors.spec.ts b/src/components/visualizations/chart/highcharts/plugins/test/dataLabelsColors.spec.ts index cd2f1b8e3c..6d47abf9c4 100644 --- a/src/components/visualizations/chart/highcharts/plugins/test/dataLabelsColors.spec.ts +++ b/src/components/visualizations/chart/highcharts/plugins/test/dataLabelsColors.spec.ts @@ -4,8 +4,10 @@ import { } from '../dataLabelsColors'; import { - DEFAULT_COLOR_PALETTE + DEFAULT_COLOR_PALETTE, + getRgbString } from '../../../../utils/color'; +import { IColorPaletteItem } from '../../../Chart'; describe('dataLabelsColors', () => { describe('isWhiteNotContrastEnough', () => { @@ -19,7 +21,8 @@ describe('dataLabelsColors', () => { it('should fullfill UX requirement for default color palette', () => { const result: boolean[] = DEFAULT_COLOR_PALETTE - .map((defaultColor: string) => isWhiteNotContrastEnough(defaultColor)); + .map((defaultColorPaletteItem: IColorPaletteItem) => getRgbString(defaultColorPaletteItem)) + .map((defaultColor: string) => isWhiteNotContrastEnough(defaultColor)); // first 17 colors should return false -> have white label const expectedValues = new Array(20).fill(false); diff --git a/src/components/visualizations/chart/test/ChartTransformation.spec.tsx b/src/components/visualizations/chart/test/ChartTransformation.spec.tsx index 80b27ce333..c2b0c44dba 100644 --- a/src/components/visualizations/chart/test/ChartTransformation.spec.tsx +++ b/src/components/visualizations/chart/test/ChartTransformation.spec.tsx @@ -1,12 +1,14 @@ // (C) 2007-2018 GoodData Corporation import * as React from 'react'; import { shallow, mount } from 'enzyme'; +import noop = require('lodash/noop'); + import ChartTransformation from '../ChartTransformation'; import * as fixtures from '../../../../../stories/test_data/fixtures'; import { TOP } from '../legend/PositionTypes'; import HighChartsRenderer from '../HighChartsRenderer'; -import noop = require('lodash/noop'); -import { IChartConfig } from '../Chart'; +import { IChartConfig, IColorPaletteItem } from '../Chart'; +import { getRgbString } from '../../utils/color'; describe('ChartTransformation', () => { const defaultProps = { @@ -35,10 +37,24 @@ describe('ChartTransformation', () => { }); it('should use custom color palette', () => { - let colorPalette; - const customColors = ['#000000', '#ff0000']; + let colors: string[] = []; + const customColorPalette = [{ + guid: 'black', + fill: { + r: 0, + g: 0, + b: 0 + } + }, { + guid: 'red', + fill: { + r: 255, + g: 0, + b: 0 + } + }]; const renderer = (params: any) => { - colorPalette = params.chartOptions.data.series.map((serie: any) => serie.color); + colors = params.chartOptions.data.series.map((serie: any) => serie.color); return
; }; const componentProps = { @@ -46,11 +62,14 @@ describe('ChartTransformation', () => { ...fixtures.barChartWithStackByAndViewByAttributes, config: { ...defaultProps.config, - colors: customColors + colorPalette: customColorPalette } }; mount(createComponent(componentProps)); - expect(colorPalette).toEqual(customColors); + expect(colors).toEqual( + customColorPalette + .map((colorPaletteItem: IColorPaletteItem) => getRgbString(colorPaletteItem)) + ); }); describe('Stacking config', () => { diff --git a/src/components/visualizations/chart/test/chartOptionsBuilder.spec.ts b/src/components/visualizations/chart/test/chartOptionsBuilder.spec.ts index 782b33a37b..65bb98b87f 100644 --- a/src/components/visualizations/chart/test/chartOptionsBuilder.spec.ts +++ b/src/components/visualizations/chart/test/chartOptionsBuilder.spec.ts @@ -37,17 +37,23 @@ import { import { DEFAULT_COLOR_PALETTE, - getLighterColor + getLighterColor, + getRgbString } from '../../utils/color'; -import { TreeMapColorStrategy, +import { + TreeMapColorStrategy, MeasureColorStrategy, AttributeColorStrategy, HeatMapColorStrategy } from '../colorFactory'; +import { IColorPaletteItem } from '../Chart'; export { IPoint }; +const FIRST_DEFAULT_COLOR_ITEM_AS_STRING = getRgbString(DEFAULT_COLOR_PALETTE[0]); +const SECOND_DEFAULT_COLOR_ITEM_AS_STRING = getRgbString(DEFAULT_COLOR_PALETTE[1]); + function getMVSTreemap(dataSet: any) { const { executionResponse: { dimensions }, @@ -584,17 +590,17 @@ describe('chartOptionsBuilder', () => { expect( pieSeriesItemData.map(pointData => pointData.color) ).toEqual([ - DEFAULT_COLOR_PALETTE[0], - DEFAULT_COLOR_PALETTE[1], - DEFAULT_COLOR_PALETTE[2] + FIRST_DEFAULT_COLOR_ITEM_AS_STRING, + SECOND_DEFAULT_COLOR_ITEM_AS_STRING, + getRgbString(DEFAULT_COLOR_PALETTE[2]) ]); expect( treemapSeriesItemData.map(pointData => pointData.color) ).toEqual([ - DEFAULT_COLOR_PALETTE[0], - DEFAULT_COLOR_PALETTE[1], - DEFAULT_COLOR_PALETTE[2] + FIRST_DEFAULT_COLOR_ITEM_AS_STRING, + SECOND_DEFAULT_COLOR_ITEM_AS_STRING, + getRgbString(DEFAULT_COLOR_PALETTE[2]) ]); }); @@ -683,15 +689,15 @@ describe('chartOptionsBuilder', () => { expect( pieSeriesItemData.map(pointData => pointData.color) ).toEqual([ - DEFAULT_COLOR_PALETTE[0], - DEFAULT_COLOR_PALETTE[1] + FIRST_DEFAULT_COLOR_ITEM_AS_STRING, + SECOND_DEFAULT_COLOR_ITEM_AS_STRING ]); expect( treemapSeriesItemData.map(pointData => pointData.color) ).toEqual([ - DEFAULT_COLOR_PALETTE[0], - DEFAULT_COLOR_PALETTE[1] + FIRST_DEFAULT_COLOR_ITEM_AS_STRING, + SECOND_DEFAULT_COLOR_ITEM_AS_STRING ]); }); @@ -755,9 +761,9 @@ describe('chartOptionsBuilder', () => { it('should fill correct series color', () => { expect(seriesData.map((seriesItem: any) => seriesItem.color)).toEqual([ - DEFAULT_COLOR_PALETTE[0], - DEFAULT_COLOR_PALETTE[1], - DEFAULT_COLOR_PALETTE[2] + FIRST_DEFAULT_COLOR_ITEM_AS_STRING, + SECOND_DEFAULT_COLOR_ITEM_AS_STRING, + getRgbString(DEFAULT_COLOR_PALETTE[2]) ]); }); @@ -824,8 +830,8 @@ describe('chartOptionsBuilder', () => { it('should fill correct series color', () => { expect(seriesData.map((seriesItem: any) => seriesItem.color)).toEqual([ - DEFAULT_COLOR_PALETTE[0], - DEFAULT_COLOR_PALETTE[1] + FIRST_DEFAULT_COLOR_ITEM_AS_STRING, + SECOND_DEFAULT_COLOR_ITEM_AS_STRING ]); }); @@ -899,6 +905,22 @@ describe('chartOptionsBuilder', () => { ] }; + const colorPalette = [{ + guid: 'red', + fill: { + r: 255, + g: 0, + b: 0 + } + }, { + guid: 'green', + fill: { + r: 0, + g: 255, + b: 0 + } + }]; + it('should fill X, Y and Z with valid values when measure buckets are not empty', () => { const executionResultData = [ [ 1, 2, 3], @@ -920,24 +942,23 @@ describe('chartOptionsBuilder', () => { } ] }; - const colorPallete = ['red', 'green']; const expectedSeries = [ { name: 'abc', - color: 'red', + color: 'rgb(255,0,0)', legendIndex: 0, data: [{ x: 1, y: 2, z: 3, format: '#.##x' }] }, { name: 'def', - color: 'green', + color: 'rgb(0,255,0)', legendIndex: 1, data: [{ x: 4, y: 5, z: 6, format: '#.##x' }] } ]; const attributeColorStrategy = new AttributeColorStrategy( - colorPallete, + colorPalette, dummyMeasureGroup, null, stackByAttribute, @@ -968,24 +989,23 @@ describe('chartOptionsBuilder', () => { items: [dummyBucketItem] }] }; - const colorPallete = ['red', 'green']; const expectedSeries = [ { name: '', - color: 'red', + color: 'rgb(255,0,0)', legendIndex: 0, data: [{ x: 0, y: 0, z: 3, format: '#.##x' }] }, { name: '', - color: 'green', + color: 'rgb(0,255,0)', legendIndex: 1, data: [{ x: 0, y: 0, z: 6, format: '#.##x' }] } ]; const attributeColorStrategy = new AttributeColorStrategy( - colorPallete, + colorPalette, dummyMeasureGroup, null, stackByAttribute, @@ -1021,24 +1041,23 @@ describe('chartOptionsBuilder', () => { } ] }; - const colorPallete = ['red', 'green']; const expectedSeries = [ { name: 'abc', - color: 'red', + color: 'rgb(255,0,0)', legendIndex: 0, data: [{ x: 0, y: 1, z: 3, format: '#.##x' }] }, { name: 'def', - color: 'green', + color: 'rgb(0,255,0)', legendIndex: 1, data: [{ x: 0, y: 4, z: 6, format: '#.##x' }] } ]; const attributeColorStrategy = new AttributeColorStrategy( - colorPallete, + colorPalette, dummyMeasureGroup, stackByAttribute, stackByAttribute, @@ -1074,24 +1093,23 @@ describe('chartOptionsBuilder', () => { } ] }; - const colorPallete = ['red', 'green']; const expectedSeries = [ { name: 'abc', - color: 'red', + color: 'rgb(255,0,0)', legendIndex: 0, data: [{ x: 1, y: 0, z: 3, format: '#.##x' }] }, { name: 'def', - color: 'green', + color: 'rgb(0,255,0)', legendIndex: 1, data: [{ x: 4, y: 0, z: 6, format: '#.##x' }] } ]; const attributeColorStrategy = new AttributeColorStrategy( - colorPallete, + colorPalette, dummyMeasureGroup, stackByAttribute, stackByAttribute, @@ -1127,24 +1145,23 @@ describe('chartOptionsBuilder', () => { } ] }; - const colorPallete = ['red', 'green']; const expectedSeries = [ { name: 'abc', - color: 'red', + color: 'rgb(255,0,0)', legendIndex: 0, data: [{ x: 1, y: 3, z: NaN, format: '#.##x' }] }, { name: 'def', - color: 'green', + color: 'rgb(0,255,0)', legendIndex: 1, data: [{ x: 4, y: 6, z: NaN, format: '#.##x' }] } ]; const attributeColorStrategy = new AttributeColorStrategy( - colorPallete, + colorPalette, dummyMeasureGroup, null, stackByAttribute, @@ -1200,29 +1217,39 @@ describe('chartOptionsBuilder', () => { } ] }; - const colorPallete = ['red', 'green', 'blue']; + const colorPaletteWithBlue = [ + ...colorPalette, + { + guid: 'blue', + fill: { + r: 0, + g: 0, + b: 255 + } + } + ]; const expectedSeries = [ { name: 'abc', - color: 'red', + color: 'rgb(255,0,0)', legendIndex: 0, data: [] as any }, { name: 'def', - color: 'green', + color: 'rgb(0,255,0)', legendIndex: 1, data: [] }, { name: 'ghi', - color: 'blue', + color: 'rgb(0,0,255)', legendIndex: 2, data: [] } ]; const attributeColorStrategy = new AttributeColorStrategy( - colorPallete, + colorPaletteWithBlue, dummyMeasureGroup, null, stackByAttributeWithThreeElements, @@ -1274,7 +1301,7 @@ describe('chartOptionsBuilder', () => { }); it('should fill correct series color', () => { - expect(seriesData[0].color).toEqual(DEFAULT_COLOR_PALETTE[0]); + expect(seriesData[0].color).toEqual(FIRST_DEFAULT_COLOR_ITEM_AS_STRING); }); it('should fill correct series legendIndex', () => { @@ -1285,7 +1312,7 @@ describe('chartOptionsBuilder', () => { expect(seriesData[0].data.length).toBe(1); expect(seriesData[0].data[0]).toMatchObject({ value: 116625456.54, - color: DEFAULT_COLOR_PALETTE[0], + color: FIRST_DEFAULT_COLOR_ITEM_AS_STRING, format: '#,##0.00', legendIndex: 0, name: 'Amount', @@ -1331,7 +1358,7 @@ describe('chartOptionsBuilder', () => { expect(seriesData[0].data.length).toBe(2); expect(seriesData[0].data[0]).toMatchObject({ value: 80406324.96, - color: DEFAULT_COLOR_PALETTE[0], + color: FIRST_DEFAULT_COLOR_ITEM_AS_STRING, format: '#,##0.00', legendIndex: 0, name: 'Direct Sales', @@ -1340,7 +1367,7 @@ describe('chartOptionsBuilder', () => { expect(seriesData[0].data[1]).toMatchObject({ value: 36219131.58, - color: DEFAULT_COLOR_PALETTE[1], + color: SECOND_DEFAULT_COLOR_ITEM_AS_STRING, format: '#,##0.00', legendIndex: 1, name: 'Inside Sales', @@ -1386,7 +1413,7 @@ describe('chartOptionsBuilder', () => { expect(seriesData[0].data[0]).toMatchObject({ id: '0', name: 'Amount', - color: DEFAULT_COLOR_PALETTE[0], + color: FIRST_DEFAULT_COLOR_ITEM_AS_STRING, showInLegend: true, legendIndex: 0, format: '#,##0.00' @@ -1397,7 +1424,7 @@ describe('chartOptionsBuilder', () => { x: 0, y: 0, value: 80406324.96, - color: DEFAULT_COLOR_PALETTE[0], + color: FIRST_DEFAULT_COLOR_ITEM_AS_STRING, format: '#,##0.00', showInLegend: false, name: 'Direct Sales' @@ -1408,7 +1435,7 @@ describe('chartOptionsBuilder', () => { x: 0, y: 1, value: 36219131.58, - color: getLighterColor(DEFAULT_COLOR_PALETTE[0], 0.4), + color: getLighterColor(FIRST_DEFAULT_COLOR_ITEM_AS_STRING, 0.4), format: '#,##0.00', showInLegend: false, name: 'Inside Sales' @@ -1451,7 +1478,7 @@ describe('chartOptionsBuilder', () => { expect(seriesData[0].data[0]).toMatchObject({ id: '0', name: 'Direct Sales', - color: DEFAULT_COLOR_PALETTE[0], + color: FIRST_DEFAULT_COLOR_ITEM_AS_STRING, showInLegend: true, legendIndex: 0, format: '#,##0.00' @@ -1459,7 +1486,7 @@ describe('chartOptionsBuilder', () => { expect(seriesData[0].data[1]).toMatchObject({ id: '1', name: 'Inside Sales', - color: DEFAULT_COLOR_PALETTE[1], + color: SECOND_DEFAULT_COLOR_ITEM_AS_STRING, showInLegend: true, legendIndex: 1, format: '#,##0.00' @@ -1470,7 +1497,7 @@ describe('chartOptionsBuilder', () => { x: 0, y: 0, value: 58427629.5, - color: DEFAULT_COLOR_PALETTE[0], + color: FIRST_DEFAULT_COLOR_ITEM_AS_STRING, format: '#,##0.00', showInLegend: false, name: 'West Coast' @@ -1481,7 +1508,7 @@ describe('chartOptionsBuilder', () => { x: 1, y: 1, value: 21978695.46, - color: getLighterColor(DEFAULT_COLOR_PALETTE[0], 0.4), + color: getLighterColor(FIRST_DEFAULT_COLOR_ITEM_AS_STRING, 0.4), format: '#,##0.00', showInLegend: false, name: 'East Coast' @@ -1492,7 +1519,7 @@ describe('chartOptionsBuilder', () => { x: 2, y: 2, value: 30180730.62, - color: DEFAULT_COLOR_PALETTE[1], + color: SECOND_DEFAULT_COLOR_ITEM_AS_STRING, format: '#,##0.00', showInLegend: false, name: 'West Coast' @@ -1503,7 +1530,7 @@ describe('chartOptionsBuilder', () => { x: 3, y: 3, value: 6038400.96, - color: getLighterColor(DEFAULT_COLOR_PALETTE[1], 0.4), + color: getLighterColor(SECOND_DEFAULT_COLOR_ITEM_AS_STRING, 0.4), format: '#,##0.00', showInLegend: false, name: 'East Coast' @@ -1546,7 +1573,7 @@ describe('chartOptionsBuilder', () => { expect(seriesData[0].data[0]).toMatchObject({ id: '0', name: 'Amount', - color: DEFAULT_COLOR_PALETTE[0], + color: FIRST_DEFAULT_COLOR_ITEM_AS_STRING, showInLegend: true, legendIndex: 0, format: '#,##0.00' @@ -1554,7 +1581,7 @@ describe('chartOptionsBuilder', () => { expect(seriesData[0].data[1]).toMatchObject({ id: '1', name: '# of Open Opps.', - color: DEFAULT_COLOR_PALETTE[1], + color: SECOND_DEFAULT_COLOR_ITEM_AS_STRING, showInLegend: true, legendIndex: 1, format: '#,##0.00' @@ -1565,7 +1592,7 @@ describe('chartOptionsBuilder', () => { x: 0, y: 0, value: 58427629.5, - color: DEFAULT_COLOR_PALETTE[0], + color: FIRST_DEFAULT_COLOR_ITEM_AS_STRING, format: '#,##0.00', showInLegend: false, name: 'Direct Sales' @@ -1576,7 +1603,7 @@ describe('chartOptionsBuilder', () => { x: 0, y: 1, value: 21978695.46, - color: getLighterColor(DEFAULT_COLOR_PALETTE[0], 0.4), + color: getLighterColor(FIRST_DEFAULT_COLOR_ITEM_AS_STRING, 0.4), format: '#,##0.00', showInLegend: false, name: 'Inside Sales' @@ -1587,7 +1614,7 @@ describe('chartOptionsBuilder', () => { x: 1, y: 1, value: 30180730.62, - color: DEFAULT_COLOR_PALETTE[1], + color: SECOND_DEFAULT_COLOR_ITEM_AS_STRING, format: '#,##0.00', showInLegend: false, name: 'Inside Sales' @@ -1598,7 +1625,7 @@ describe('chartOptionsBuilder', () => { x: 1, y: 0, value: 6038400.96, - color: getLighterColor(DEFAULT_COLOR_PALETTE[1], 0.4), + color: getLighterColor(SECOND_DEFAULT_COLOR_ITEM_AS_STRING, 0.4), format: '#,##0.00', showInLegend: false, name: 'Direct Sales' @@ -2187,8 +2214,8 @@ describe('chartOptionsBuilder', () => { it('should fill correct series color', () => { expect(seriesData.map((seriesItem: any) => seriesItem.color)).toEqual([ - DEFAULT_COLOR_PALETTE[0], - DEFAULT_COLOR_PALETTE[1] + FIRST_DEFAULT_COLOR_ITEM_AS_STRING, + SECOND_DEFAULT_COLOR_ITEM_AS_STRING ]); }); @@ -2587,7 +2614,10 @@ describe('chartOptionsBuilder', () => { it('should assign 3 colors from default colorPalette', () => { const seriesColors = chartOptions.data.series.map((serie: any) => serie.color); - expect(seriesColors).toEqual(DEFAULT_COLOR_PALETTE.slice(0, 3)); + expect(seriesColors).toEqual( + DEFAULT_COLOR_PALETTE.slice(0, 3) + .map((defaultColor: IColorPaletteItem) => getRgbString(defaultColor)) + ); }); it('should assign correct tooltip function', () => { diff --git a/src/components/visualizations/chart/test/colorFactory.spec.ts b/src/components/visualizations/chart/test/colorFactory.spec.ts index 41c50b5615..27de4c7653 100644 --- a/src/components/visualizations/chart/test/colorFactory.spec.ts +++ b/src/components/visualizations/chart/test/colorFactory.spec.ts @@ -10,9 +10,14 @@ import { import { getMVS } from './helper'; -import { DEFAULT_COLOR_PALETTE, HEATMAP_BLUE_COLOR_PALETTE } from '../../utils/color'; +import { + DEFAULT_COLOR_PALETTE, + HEATMAP_BLUE_COLOR_PALETTE, + getRgbString +} from '../../utils/color'; import * as fixtures from '../../../../../stories/test_data/fixtures'; +import { IColorPalette, IColorPaletteItem } from '../Chart'; function getColorsFromStrategy(strategy: IColorStrategy): string[] { const res: string[] = []; @@ -32,12 +37,47 @@ function getColorsFromStrategy(strategy: IColorStrategy): string[] { } describe('ColorFactory', () => { + const customPalette = [ + { + guid: '01', + fill: { + r: 50, + g: 50, + b: 50 + } + }, + { + guid: '02', + fill: { + r: 100, + g: 100, + b: 100 + } + }, + { + guid: '03', + fill: { + r: 150, + g: 150, + b: 150 + } + }, + { + guid: '04', + fill: { + r: 200, + g: 200, + b: 200 + } + } + ]; + it('should return AttributeColorStrategy with two colors from default color palette', () => { const [measureGroup, viewByAttribute, stackByAttribute] = getMVS(fixtures.barChartWithStackByAndViewByAttributes); const { afm } = fixtures.barChartWithStackByAndViewByAttributes.executionRequest; const type = 'bar'; - const colorPalette: string[] = undefined; + const colorPalette: IColorPalette = undefined; const colorStrategy = ColorFactory.getColorStrategy( colorPalette, @@ -51,7 +91,11 @@ describe('ColorFactory', () => { const updatedPalette = getColorsFromStrategy(colorStrategy); expect(colorStrategy).toBeInstanceOf(AttributeColorStrategy); - expect(updatedPalette).toEqual(DEFAULT_COLOR_PALETTE.slice(0, 2)); + expect(updatedPalette).toEqual( + DEFAULT_COLOR_PALETTE + .slice(0, 2) + .map((defaultColorPaletteItem: IColorPaletteItem) => getRgbString(defaultColorPaletteItem)) + ); }); it('should return AttributeColorStrategy with two colors from custom color palette', () => { @@ -59,7 +103,28 @@ describe('ColorFactory', () => { getMVS(fixtures.barChartWithStackByAndViewByAttributes); const { afm } = fixtures.barChartWithStackByAndViewByAttributes.executionRequest; const type = 'bar'; - const colorPalette = ['a', 'b', 'c']; + const colorPalette = [{ + guid: 'red', + fill: { + r: 255, + g: 0, + b: 0 + } + }, { + guid: 'green', + fill: { + r: 0, + g: 255, + b: 0 + } + }, { + guid: 'blue', + fill: { + r: 0, + g: 0, + b: 255 + } + }]; const colorStrategy = ColorFactory.getColorStrategy( colorPalette, @@ -73,7 +138,11 @@ describe('ColorFactory', () => { const updatedPalette = getColorsFromStrategy(colorStrategy); expect(colorStrategy).toBeInstanceOf(AttributeColorStrategy); - expect(updatedPalette).toEqual(colorPalette.slice(0, 2)); + expect(updatedPalette).toEqual( + colorPalette + .slice(0, 2) + .map((defaultColorPaletteItem: IColorPaletteItem) => getRgbString(defaultColorPaletteItem)) + ); }); it('should return TreeMapColorStrategy strategy with two colors from default color palette', () => { @@ -81,7 +150,7 @@ describe('ColorFactory', () => { getMVS(fixtures.treemapWithMetricViewByAndStackByAttribute); const { afm } = fixtures.treemapWithMetricViewByAndStackByAttribute.executionRequest; const type = 'treemap'; - const colorPalette: string[] = undefined; + const colorPalette: IColorPalette = undefined; const colorStrategy = ColorFactory.getColorStrategy( colorPalette, @@ -95,7 +164,11 @@ describe('ColorFactory', () => { const updatedPalette = getColorsFromStrategy(colorStrategy); expect(colorStrategy).toBeInstanceOf(TreeMapColorStrategy); - expect(updatedPalette).toEqual(DEFAULT_COLOR_PALETTE.slice(0, 1)); + expect(updatedPalette).toEqual( + DEFAULT_COLOR_PALETTE + .slice(0, 1) + .map((defaultColorPaletteItem: IColorPaletteItem) => getRgbString(defaultColorPaletteItem)) + ); }); it('should return HeatMapColorStrategy strategy with two colors from default color palette', () => { @@ -103,7 +176,7 @@ describe('ColorFactory', () => { getMVS(fixtures.heatmapMetricRowColumn); const { afm } = fixtures.heatmapMetricRowColumn.executionRequest; const type = 'heatmap'; - const colorPalette: string[] = undefined; + const colorPalette: IColorPalette = undefined; const colorStrategy = ColorFactory.getColorStrategy( colorPalette, @@ -115,13 +188,9 @@ describe('ColorFactory', () => { ); expect(colorStrategy).toBeInstanceOf(HeatMapColorStrategy); - expect(colorStrategy.getColorByIndex(0)).toEqual(HEATMAP_BLUE_COLOR_PALETTE[0]); - expect(colorStrategy.getColorByIndex(1)).toEqual(HEATMAP_BLUE_COLOR_PALETTE[1]); - expect(colorStrategy.getColorByIndex(2)).toEqual(HEATMAP_BLUE_COLOR_PALETTE[2]); - expect(colorStrategy.getColorByIndex(3)).toEqual(HEATMAP_BLUE_COLOR_PALETTE[3]); - expect(colorStrategy.getColorByIndex(4)).toEqual(HEATMAP_BLUE_COLOR_PALETTE[4]); - expect(colorStrategy.getColorByIndex(5)).toEqual(HEATMAP_BLUE_COLOR_PALETTE[5]); - expect(colorStrategy.getColorByIndex(6)).toEqual(HEATMAP_BLUE_COLOR_PALETTE[6]); + [0, 1, 2, 3, 4, 5, 6].map((colorIndex: number) => + expect(colorStrategy.getColorByIndex(colorIndex)).toEqual(HEATMAP_BLUE_COLOR_PALETTE[colorIndex]) + ); }); it('should just return the original palette if there are no pop measures shorten to cover all legend items', @@ -129,7 +198,7 @@ describe('ColorFactory', () => { const [measureGroup, viewByAttribute, stackByAttribute] = getMVS(fixtures.barChartWithoutAttributes); const { afm } = fixtures.barChartWithoutAttributes.executionRequest; const type = 'column'; - const colorPalette: string[] = undefined; + const colorPalette: IColorPalette = undefined; const colorStrategy = ColorFactory.getColorStrategy( colorPalette, @@ -151,7 +220,6 @@ describe('ColorFactory', () => { getMVS(fixtures.barChartWithPopMeasureAndViewByAttribute); const { afm } = fixtures.barChartWithPopMeasureAndViewByAttribute.executionRequest; const type = 'column'; - const customPalette = ['rgb(50,50,50)', 'rgb(100,100,100)', 'rgb(150,150,150)', 'rgb(200,200,200)']; const colorStrategy = ColorFactory.getColorStrategy( customPalette, @@ -173,8 +241,6 @@ describe('ColorFactory', () => { const { afm } = fixtures.barChartWithPreviousPeriodMeasure.executionRequest; const type = 'column'; - const customPalette = ['rgb(50,50,50)', 'rgb(100,100,100)', 'rgb(150,150,150)', 'rgb(200,200,200)']; - const colorStrategy = ColorFactory.getColorStrategy( customPalette, measureGroup, @@ -195,8 +261,6 @@ describe('ColorFactory', () => { const { afm } = fixtures.barChartWith6PopMeasuresAndViewByAttribute.executionRequest; const type = 'column'; - const customPalette = ['rgb(50,50,50)', 'rgb(100,100,100)', 'rgb(150,150,150)', 'rgb(200,200,200)']; - const colorStrategy = ColorFactory.getColorStrategy( customPalette, measureGroup, @@ -220,8 +284,6 @@ describe('ColorFactory', () => { const { afm } = fixtures.barChartWith6PreviousPeriodMeasures.executionRequest; const type = 'column'; - const customPalette = ['rgb(50,50,50)', 'rgb(100,100,100)', 'rgb(150,150,150)', 'rgb(200,200,200)']; - const colorStrategy = ColorFactory.getColorStrategy( customPalette, measureGroup, diff --git a/src/components/visualizations/utils/color.ts b/src/components/visualizations/utils/color.ts index 439cdb98a1..cbaf99523c 100644 --- a/src/components/visualizations/utils/color.ts +++ b/src/components/visualizations/utils/color.ts @@ -1,10 +1,13 @@ // (C) 2007-2018 GoodData Corporation +import isEmpty = require('lodash/isEmpty'); +import { IColorPalette, IColorPaletteItem, IChartConfig } from '../chart/Chart'; + export const WHITE = 'rgb(255, 255, 255)'; export const BLACK = 'rgb(0, 0, 0)'; export const GRAY = 'rgb(201, 213, 223)'; export const AXIS_LINE_COLOR = '#d5d5d5'; -export const DEFAULT_COLOR_PALETTE = [ +export const DEFAULT_COLORS = [ 'rgb(20,178,226)', 'rgb(0,193,141)', 'rgb(229,77,66)', @@ -30,6 +33,89 @@ export const DEFAULT_COLOR_PALETTE = [ 'rgb(239,197,194)' ]; +export const DEFAULT_COLOR_PALETTE = [ + { + guid: 'blue', + fill: { r: 20, g: 178, b: 226 } + }, + { + guid: 'green', + fill: { r: 0, g: 193, b: 141 } + }, + { + guid: 'red', + fill: { r: 229, g: 77, b: 66 } + }, + { + guid: 'orange', + fill: { r: 241, g: 134, b: 0 } + }, + { + guid: 'purple', + fill: { r: 171, g: 85, b: 163 } + }, + { + guid: 'yellow', + fill: { r: 244, g: 213, b: 33 } + }, + { + guid: 'grey', + fill: { r: 148, g: 161, b: 174 } + }, + { + guid: 'blue-light', + fill: { r: 107, g: 191, b: 216 } + }, + { + guid: 'violet-light', + fill: { r: 181, g: 136, b: 177 } + }, + { + guid: 'red-light', + fill: { r: 238, g: 135, b: 128 } + }, + { + guid: 'orange-light', + fill: { r: 241, g: 171, b: 84 } + }, + { + guid: 'green-light', + fill: { r: 133, g: 209, b: 188 } + }, + { + guid: 'blue-dark', + fill: { r: 41, g: 117, b: 170 } + }, + { + guid: 'green-dark', + fill: { r: 4, g: 140, b: 103 } + }, + { + guid: 'red-dark', + fill: { r: 181, g: 60, b: 51 } + }, + { + guid: 'orange-dark', + fill: { r: 163, g: 101, b: 46 } + }, + { + guid: 'purple-dark', + fill: { r: 140, g: 57, b: 132 } + }, + { + guid: 'azure', + fill: { r: 136, g: 219, b: 244 } + }, + { + guid: 'green-celadon', + fill: { r: 189, g: 234, b: 222 } + }, + { + guid: 'pink-pale', + fill: { r: 239, g: 197, b: 194 } + } +]; + export const HEATMAP_BLUE_COLOR_PALETTE = [ 'rgb(255,255,255)', 'rgb(197,236,248)', @@ -79,3 +165,34 @@ export function normalizeColorToRGB(color: string) { return `rgb(${[r, g, b].map(value => (parseInt(value, 16).toString(10))).join(', ')})`; }); } + +export function getColorPaletteFromColors(colors: string[]): IColorPalette { + try { + return colors.map((color: string, index: number) => { + const { R, G, B } = parseRGBColorCode(normalizeColorToRGB(color)); + if (isNaN(R) || isNaN(G) || isNaN(B)) { + throw Error; + } + return { + guid: String(index), + fill: { + r: R, + g: G, + b: B + } + }; + }); + } catch (_ignored) { + return DEFAULT_COLOR_PALETTE; + } +} + +export function getRgbString(color: IColorPaletteItem): string { + return `rgb(${color.fill.r},${color.fill.g},${color.fill.b})`; +} + +export function getValidColorPalette(config: IChartConfig) { + return isEmpty(config.colorPalette) ? + (isEmpty(config.colors) ? DEFAULT_COLOR_PALETTE : getColorPaletteFromColors(config.colors)) + : config.colorPalette; +} diff --git a/src/components/visualizations/utils/test/color.spec.ts b/src/components/visualizations/utils/test/color.spec.ts index 11cc7ba874..b0a6230426 100644 --- a/src/components/visualizations/utils/test/color.spec.ts +++ b/src/components/visualizations/utils/test/color.spec.ts @@ -1,5 +1,5 @@ // (C) 2007-2018 GoodData Corporation -import { getLighterColor, normalizeColorToRGB } from '../color'; +import { getLighterColor, normalizeColorToRGB, getColorPaletteFromColors, DEFAULT_COLOR_PALETTE, getValidColorPalette } from '../color'; describe('Transformation', () => { describe('Lighten color', () => { @@ -25,3 +25,59 @@ describe('normalizeColorToRGB', () => { ).toEqual(expectedColor); }); }); + +describe('getColorPaletteFromColors', () => { + it('should return colorPalette made from string of rgb colors', () => { + const colors = [ 'rgb(12,24,8}', 'rgb(9,10,11' ]; + const expectedResult = [ + { guid: '0', fill: { r: 12, g: 24, b: 8 } }, + { guid: '1', fill: { r: 9, g: 10, b: 11 } } + ]; + const result = getColorPaletteFromColors(colors); + + expect(result).toEqual(expectedResult); + }); + + it('should return default palette when invalid colors are provided', () => { + const colors = [ 'invalid', 'colors' ]; + const result = getColorPaletteFromColors(colors); + + expect(result).toEqual(DEFAULT_COLOR_PALETTE); + }); +}); + +describe('getValidColorPalette', () => { + it('should return default color palette when colors and colorPalette are not defined', () => { + const config = {}; + const expectedResult = DEFAULT_COLOR_PALETTE; + const result = getValidColorPalette(config); + + expect(result).toEqual(expectedResult); + }); + + it('should return colors when color palette is not defined', () => { + const config = { + colors: [ 'rgb(1,24,8}', 'rgb(90,10,11' ] + }; + const expectedResult = [ + { guid: '0', fill: { r: 1, g: 24, b: 8 } }, + { guid: '1', fill: { r: 90, g: 10, b: 11 } } + ]; + const result = getValidColorPalette(config); + + expect(result).toEqual(expectedResult); + }); + + it('should return color palette when both are defined', () => { + const config = { + colors: [ 'rgb(1,24,8}', 'rgb(90,10,11' ], + colorPalette: [ + { guid: '0', fill: { r: 1, g: 1, b: 2 } }, + { guid: '1', fill: { r: 9, g: 1, b: 1 } } + ] + }; + const result = getValidColorPalette(config); + + expect(result).toEqual(config.colorPalette); + }); +}); diff --git a/src/index.ts b/src/index.ts index 873fa9fb56..604651969b 100644 --- a/src/index.ts +++ b/src/index.ts @@ -42,7 +42,8 @@ import { ScatterPlot } from './components/ScatterPlot'; import { ComboChart } from './components/ComboChart'; import { FunnelChart } from './components/FunnelChart'; import { Heatmap } from './components/Heatmap'; -import Chart, { ILegendConfig, IChartConfig } from './components/visualizations/chart/Chart'; +import Chart, + { ILegendConfig, IChartConfig, IColorPalette, IColorPaletteItem } from './components/visualizations/chart/Chart'; import ChartTransformation from './components/visualizations/chart/ChartTransformation'; import { RuntimeError } from './errors/RuntimeError'; @@ -84,6 +85,8 @@ export { IDrillableItem, ILegendConfig, IChartConfig, + IColorPalette, + IColorPaletteItem, IPushData, isEmptyResult, Kpi, diff --git a/stories/__screenshots__/storybook_AFM_components_Treemap_-_custom_colors_0_screenshot-wrapper_0_desktop.png b/stories/__screenshots__/storybook_AFM_components_Treemap_-_custom_colors_0_screenshot-wrapper_0_desktop.png old mode 100755 new mode 100644 index 147f21022e..857cf55c84 Binary files a/stories/__screenshots__/storybook_AFM_components_Treemap_-_custom_colors_0_screenshot-wrapper_0_desktop.png and b/stories/__screenshots__/storybook_AFM_components_Treemap_-_custom_colors_0_screenshot-wrapper_0_desktop.png differ diff --git a/stories/__screenshots__/storybook_Core_components_BarChart_-_custom_colors_0_screenshot-wrapper_0_desktop.png b/stories/__screenshots__/storybook_Core_components_BarChart_-_custom_colors_0_screenshot-wrapper_0_desktop.png deleted file mode 100755 index a4c97f5b31..0000000000 Binary files a/stories/__screenshots__/storybook_Core_components_BarChart_-_custom_colors_0_screenshot-wrapper_0_desktop.png and /dev/null differ diff --git a/stories/__screenshots__/storybook_Core_components_BarChart_-_custom_colors_by_colors_0_screenshot-wrapper_0_desktop.png b/stories/__screenshots__/storybook_Core_components_BarChart_-_custom_colors_by_colors_0_screenshot-wrapper_0_desktop.png new file mode 100644 index 0000000000..6efa32276b Binary files /dev/null and b/stories/__screenshots__/storybook_Core_components_BarChart_-_custom_colors_by_colors_0_screenshot-wrapper_0_desktop.png differ diff --git a/stories/__screenshots__/storybook_Core_components_BarChart_-_custom_colors_by_palette_0_screenshot-wrapper_0_desktop.png b/stories/__screenshots__/storybook_Core_components_BarChart_-_custom_colors_by_palette_0_screenshot-wrapper_0_desktop.png new file mode 100644 index 0000000000..6efa32276b Binary files /dev/null and b/stories/__screenshots__/storybook_Core_components_BarChart_-_custom_colors_by_palette_0_screenshot-wrapper_0_desktop.png differ diff --git a/stories/__screenshots__/storybook_Core_components_BarChart_-_when_both_color_props_prefer_palette_0_screenshot-wrapper_0_desktop.png b/stories/__screenshots__/storybook_Core_components_BarChart_-_when_both_color_props_prefer_palette_0_screenshot-wrapper_0_desktop.png new file mode 100644 index 0000000000..6efa32276b Binary files /dev/null and b/stories/__screenshots__/storybook_Core_components_BarChart_-_when_both_color_props_prefer_palette_0_screenshot-wrapper_0_desktop.png differ diff --git a/stories/__screenshots__/storybook_Core_components_Treemap_-_custom_colors_0_screenshot-wrapper_0_desktop.png b/stories/__screenshots__/storybook_Core_components_Treemap_-_custom_colors_0_screenshot-wrapper_0_desktop.png old mode 100755 new mode 100644 index 147f21022e..857cf55c84 Binary files a/stories/__screenshots__/storybook_Core_components_Treemap_-_custom_colors_0_screenshot-wrapper_0_desktop.png and b/stories/__screenshots__/storybook_Core_components_Treemap_-_custom_colors_0_screenshot-wrapper_0_desktop.png differ diff --git a/stories/__screenshots__/storybook_Core_components_Treemap_-_custom_colors_by_hexa_0_screenshot-wrapper_0_desktop.png b/stories/__screenshots__/storybook_Core_components_Treemap_-_custom_colors_by_hexa_0_screenshot-wrapper_0_desktop.png new file mode 100644 index 0000000000..ccc7d652d2 Binary files /dev/null and b/stories/__screenshots__/storybook_Core_components_Treemap_-_custom_colors_by_hexa_0_screenshot-wrapper_0_desktop.png differ diff --git a/stories/__screenshots__/storybook_Internal_HighCharts_ChartTransformation_-_Custom_color_pallete_0_screenshot-wrapper_0_desktop.png b/stories/__screenshots__/storybook_Internal_HighCharts_ChartTransformation_-_Custom_color_palette_0_screenshot-wrapper_0_desktop.png similarity index 100% rename from stories/__screenshots__/storybook_Internal_HighCharts_ChartTransformation_-_Custom_color_pallete_0_screenshot-wrapper_0_desktop.png rename to stories/__screenshots__/storybook_Internal_HighCharts_ChartTransformation_-_Custom_color_palette_0_screenshot-wrapper_0_desktop.png diff --git a/stories/__screenshots__/storybook_Internal_HighCharts_ChartTransformation_-_Treemap_with_measures_only_0_screenshot-wrapper_0_desktop.png b/stories/__screenshots__/storybook_Internal_HighCharts_ChartTransformation_-_Treemap_with_measures_only_0_screenshot-wrapper_0_desktop.png old mode 100755 new mode 100644 index 68f9a31205..2b54cdd0eb Binary files a/stories/__screenshots__/storybook_Internal_HighCharts_ChartTransformation_-_Treemap_with_measures_only_0_screenshot-wrapper_0_desktop.png and b/stories/__screenshots__/storybook_Internal_HighCharts_ChartTransformation_-_Treemap_with_measures_only_0_screenshot-wrapper_0_desktop.png differ diff --git a/stories/__screenshots__/storybook_Internal_HighCharts_ChartTransformation_-_Treemap_with_viewBy_attribute_0_screenshot-wrapper_0_desktop.png b/stories/__screenshots__/storybook_Internal_HighCharts_ChartTransformation_-_Treemap_with_viewBy_attribute_0_screenshot-wrapper_0_desktop.png old mode 100755 new mode 100644 index 15bcc6a454..dab4de7e8f Binary files a/stories/__screenshots__/storybook_Internal_HighCharts_ChartTransformation_-_Treemap_with_viewBy_attribute_0_screenshot-wrapper_0_desktop.png and b/stories/__screenshots__/storybook_Internal_HighCharts_ChartTransformation_-_Treemap_with_viewBy_attribute_0_screenshot-wrapper_0_desktop.png differ diff --git a/stories/core_components/BarChart.tsx b/stories/core_components/BarChart.tsx index 118e005dfe..73fb893f57 100644 --- a/stories/core_components/BarChart.tsx +++ b/stories/core_components/BarChart.tsx @@ -5,7 +5,7 @@ import { screenshotWrap } from '@gooddata/test-storybook'; import { BarChart } from '../../src'; import { onErrorHandler } from '../mocks'; -import { CUSTOM_COLORS } from '../data/colors'; +import { CUSTOM_COLOR_PALETTE, CUSTOM_COLORS } from '../data/colors'; import { ATTRIBUTE_1, ATTRIBUTE_2, @@ -64,13 +64,30 @@ storiesOf('Core components/BarChart', module)
) )) - .add('custom colors', () => ( + .add('custom colors by palette', () => ( screenshotWrap(
+
+ ) + )) + .add('custom colors by colors', () => ( + screenshotWrap( +
+ ) )) + .add('when both color props, prefer palette', () => ( + screenshotWrap( +
+ +
+ ) + )) .add('sorted by attribute', () => ( screenshotWrap(
diff --git a/stories/core_components/ColumnChart.tsx b/stories/core_components/ColumnChart.tsx index b04679d782..b38698c55b 100644 --- a/stories/core_components/ColumnChart.tsx +++ b/stories/core_components/ColumnChart.tsx @@ -5,7 +5,7 @@ import { screenshotWrap } from '@gooddata/test-storybook'; import { ColumnChart } from '../../src'; import { onErrorHandler } from '../mocks'; -import { CUSTOM_COLORS } from '../data/colors'; +import { CUSTOM_COLOR_PALETTE } from '../data/colors'; import { ATTRIBUTE_1, ATTRIBUTE_1_WITH_ALIAS, @@ -56,7 +56,7 @@ storiesOf('Core components/ColumnChart', module) projectId="storybook" measures={[MEASURE_1]} viewBy={ATTRIBUTE_1} - config={{ colors: CUSTOM_COLORS }} + config={{ colorPalette: CUSTOM_COLOR_PALETTE }} onError={onErrorHandler} LoadingComponent={null} ErrorComponent={null} diff --git a/stories/core_components/ComboChart.tsx b/stories/core_components/ComboChart.tsx index 04dc779992..a27b2c1435 100644 --- a/stories/core_components/ComboChart.tsx +++ b/stories/core_components/ComboChart.tsx @@ -5,7 +5,7 @@ import { screenshotWrap } from '@gooddata/test-storybook'; import { ComboChart } from '../../src'; import { onErrorHandler } from '../mocks'; -import { CUSTOM_COLORS } from '../data/colors'; +import { CUSTOM_COLOR_PALETTE } from '../data/colors'; import { ATTRIBUTE_1, MEASURE_1, @@ -46,7 +46,7 @@ storiesOf('Core components/ComboChart', module) onError={onErrorHandler} LoadingComponent={null} ErrorComponent={null} - config={{ colors: CUSTOM_COLORS }} + config={{ colorPalette: CUSTOM_COLOR_PALETTE }} />
) diff --git a/stories/core_components/LineChart.tsx b/stories/core_components/LineChart.tsx index acfedfde68..0e1b357c64 100644 --- a/stories/core_components/LineChart.tsx +++ b/stories/core_components/LineChart.tsx @@ -5,7 +5,7 @@ import { screenshotWrap } from '@gooddata/test-storybook'; import { LineChart } from '../../src'; import { onErrorHandler } from '../mocks'; -import { CUSTOM_COLORS } from '../data/colors'; +import { CUSTOM_COLOR_PALETTE } from '../data/colors'; import { ATTRIBUTE_1, ATTRIBUTE_1_WITH_ALIAS, @@ -77,7 +77,7 @@ storiesOf('Core components/LineChart', module) projectId="storybook" measures={[MEASURE_1]} trendBy={ATTRIBUTE_1} - config={{ colors: CUSTOM_COLORS }} + config={{ colorPalette: CUSTOM_COLOR_PALETTE }} onError={onErrorHandler} LoadingComponent={null} ErrorComponent={null} diff --git a/stories/core_components/Treemap.tsx b/stories/core_components/Treemap.tsx index 029846498d..8d13b9dfd0 100644 --- a/stories/core_components/Treemap.tsx +++ b/stories/core_components/Treemap.tsx @@ -4,7 +4,7 @@ import { storiesOf } from '@storybook/react'; import { screenshotWrap } from '@gooddata/test-storybook'; import { Treemap } from '../../src'; -import { CUSTOM_COLORS } from '../data/colors'; +import { CUSTOM_COLOR_PALETTE } from '../data/colors'; import { onErrorHandler } from '../mocks'; import { ATTRIBUTE_1, @@ -107,12 +107,28 @@ storiesOf('Core components/Treemap', module) projectId="storybook" measures={[MEASURE_1]} viewBy={ATTRIBUTE_1} - config={{ colors: CUSTOM_COLORS }} + config={{ colorPalette: CUSTOM_COLOR_PALETTE }} onError={onErrorHandler} />
) )) + .add('custom colors by hexa', () => ( + screenshotWrap( +
+ +
+ ) + )) .add('with German number format', () => ( screenshotWrap(
diff --git a/stories/data/colors.ts b/stories/data/colors.ts index 8a9658a9d7..c5c1ddc4aa 100644 --- a/stories/data/colors.ts +++ b/stories/data/colors.ts @@ -1,8 +1,43 @@ +import { IColorPalette } from '../../src/index'; + // (C) 2007-2018 GoodData Corporation export const CUSTOM_COLORS: string[] = [ - 'rgba(195, 49, 73, 1)', - 'rgba(168, 194, 86, 1)', - 'rgba(243, 217, 177, 1)', - 'rgba(194, 153, 121, 1)', - 'rgba(162, 37, 34, 1)' + 'rgb(195, 49, 73)', + 'rgb(168, 194, 86)', + 'rgb(243, 217, 177)', + 'rgb(194, 153, 121)', + 'rgb(162, 37, 34)' +]; + +export const CUSTOM_COLOR_PALETTE: IColorPalette = [ + { + guid: '01', + fill: { + r: 195, g: 49, b: 73 + } + }, + { + guid: '02', + fill: { + r: 168, g: 194, b: 86 + } + }, + { + guid: '03', + fill: { + r: 243, g: 217, b: 177 + } + }, + { + guid: '04', + fill: { + r: 194, g: 153, b: 121 + } + }, + { + guid: '05', + fill: { + r: 162, g: 37, b: 34 + } + } ]; diff --git a/stories/internal/ChartProperties.tsx b/stories/internal/ChartProperties.tsx index cf0ec11557..811ea40cd4 100644 --- a/stories/internal/ChartProperties.tsx +++ b/stories/internal/ChartProperties.tsx @@ -33,7 +33,7 @@ storiesOf('Internal/HighCharts/ChartProperties', module) position: 'top' }, legendLayout: 'vertical', - colors: fixtures.customPalette, + colorPalette: fixtures.customPalette, grid: { enabled: false } @@ -63,7 +63,7 @@ storiesOf('Internal/HighCharts/ChartProperties', module) position: 'top' }, legendLayout: 'vertical', - colors: fixtures.customPalette, + colorPalette: fixtures.customPalette, xaxis: { rotation: '60' } @@ -93,7 +93,7 @@ storiesOf('Internal/HighCharts/ChartProperties', module) position: 'top' }, legendLayout: 'vertical', - colors: fixtures.customPalette, + colorPalette: fixtures.customPalette, yaxis: { min: '500000', max: '1000000' @@ -124,7 +124,7 @@ storiesOf('Internal/HighCharts/ChartProperties', module) position: 'top' }, legendLayout: 'vertical', - colors: fixtures.customPalette, + colorPalette: fixtures.customPalette, xaxis: { visible: false }, @@ -157,7 +157,7 @@ storiesOf('Internal/HighCharts/ChartProperties', module) position: 'top' }, legendLayout: 'vertical', - colors: fixtures.customPalette, + colorPalette: fixtures.customPalette, xaxis: { labelsEnabled: false }, diff --git a/stories/internal/ChartTransformation.tsx b/stories/internal/ChartTransformation.tsx index e7ef085663..839912f6b9 100644 --- a/stories/internal/ChartTransformation.tsx +++ b/stories/internal/ChartTransformation.tsx @@ -24,7 +24,7 @@ function getChart({ legendPosition = 'top', legendResponsive = false, dataSet = fixtures.barChartWithoutAttributes, - colors, + colorPalette, width, height, minHeight, @@ -42,7 +42,7 @@ function getChart({ position: legendPosition, responsive: legendResponsive }, - colors + colorPalette }} height={chartHeight} width={chartWidth} @@ -171,7 +171,7 @@ storiesOf('Internal/HighCharts/ChartTransformation', module) position: 'right' }, legendLayout: 'horizontal', - colors: fixtures.customPalette, + colorPalette: fixtures.customPalette, mdObject: fixtures.bubbleChartWith3MetricsAndAttributeMd.mdObject }} {...dataSet} @@ -203,7 +203,7 @@ storiesOf('Internal/HighCharts/ChartTransformation', module) position: 'right' }, legendLayout: 'horizontal', - colors: fixtures.customPalette, + colorPalette: fixtures.customPalette, mdObject: dataSet.mdObject }} {...dataSet} @@ -236,7 +236,7 @@ storiesOf('Internal/HighCharts/ChartTransformation', module) position: 'top' }, legendLayout: 'horizontal', - colors: fixtures.customPalette + colorPalette: fixtures.customPalette }} {...dataSet} onDataTooLarge={dataLarge} @@ -264,7 +264,7 @@ storiesOf('Internal/HighCharts/ChartTransformation', module) position: 'top' }, legendLayout: 'horizontal', - colors: fixtures.customPalette + colorPalette: fixtures.customPalette }} {...dataSet} onDataTooLarge={identity} @@ -291,7 +291,7 @@ storiesOf('Internal/HighCharts/ChartTransformation', module) position: 'top' }, legendLayout: 'horizontal', - colors: fixtures.customPalette + colorPalette: fixtures.customPalette }} {...dataSet} onDataTooLarge={identity} @@ -317,7 +317,7 @@ storiesOf('Internal/HighCharts/ChartTransformation', module) position: 'top' }, legendLayout: 'horizontal', - colors: fixtures.customPalette + colorPalette: fixtures.customPalette }} {...dataSet} onDataTooLarge={identity} @@ -343,7 +343,7 @@ storiesOf('Internal/HighCharts/ChartTransformation', module) position: 'right' }, legendLayout: 'horizontal', - colors: fixtures.customPalette + colorPalette: fixtures.customPalette }} {...dataSet} onDataTooLarge={identity} @@ -370,7 +370,7 @@ storiesOf('Internal/HighCharts/ChartTransformation', module) position: 'top' }, legendLayout: 'vertical', - colors: fixtures.customPalette + colorPalette: fixtures.customPalette }} {...dataSet} onDataTooLarge={identity} @@ -397,7 +397,7 @@ storiesOf('Internal/HighCharts/ChartTransformation', module) position: 'top' }, legendLayout: 'vertical', - colors: fixtures.customPalette + colorPalette: fixtures.customPalette }} {...dataSet} onDataTooLarge={identity} @@ -424,7 +424,7 @@ storiesOf('Internal/HighCharts/ChartTransformation', module) position: 'top' }, legendLayout: 'vertical', - colors: fixtures.customPalette + colorPalette: fixtures.customPalette }} {...dataSet} onDataTooLarge={identity} @@ -451,7 +451,7 @@ storiesOf('Internal/HighCharts/ChartTransformation', module) position: 'top' }, legendLayout: 'vertical', - colors: fixtures.customPalette + colorPalette: fixtures.customPalette }} {...dataSet} onDataTooLarge={identity} @@ -478,7 +478,7 @@ storiesOf('Internal/HighCharts/ChartTransformation', module) position: 'bottom' }, legendLayout: 'vertical', - colors: fixtures.customPalette + colorPalette: fixtures.customPalette }} {...dataSet} onDataTooLarge={identity} @@ -505,7 +505,7 @@ storiesOf('Internal/HighCharts/ChartTransformation', module) position: 'right' }, legendLayout: 'horizontal', - colors: fixtures.customPalette + colorPalette: fixtures.customPalette }} {...dataSet} onDataTooLarge={identity} @@ -532,7 +532,7 @@ storiesOf('Internal/HighCharts/ChartTransformation', module) position: 'left' }, legendLayout: 'horizontal', - colors: fixtures.customPalette + colorPalette: fixtures.customPalette }} {...dataSet} onDataTooLarge={identity} @@ -559,7 +559,7 @@ storiesOf('Internal/HighCharts/ChartTransformation', module) position: 'left' }, legendLayout: 'horizontal', - colors: fixtures.customPalette + colorPalette: fixtures.customPalette }} {...dataSet} onDataTooLarge={identity} @@ -586,7 +586,7 @@ storiesOf('Internal/HighCharts/ChartTransformation', module) position: 'left' }, legendLayout: 'horizontal', - colors: fixtures.customPalette + colorPalette: fixtures.customPalette }} {...dataSet} onDataTooLarge={identity} @@ -609,7 +609,7 @@ storiesOf('Internal/HighCharts/ChartTransformation', module) config={{ type: 'funnel', legendLayout: 'horizontal', - colors: fixtures.customPalette + colorPalette: fixtures.customPalette }} {...dataSet} onDataTooLarge={identity} @@ -632,7 +632,7 @@ storiesOf('Internal/HighCharts/ChartTransformation', module) config={{ type: 'funnel', legendLayout: 'horizontal', - colors: fixtures.customPalette + colorPalette: fixtures.customPalette }} {...dataSet} onDataTooLarge={identity} @@ -655,7 +655,7 @@ storiesOf('Internal/HighCharts/ChartTransformation', module) config={{ type: 'funnel', legendLayout: 'horizontal', - colors: fixtures.customPalette + colorPalette: fixtures.customPalette }} {...dataSet} onDataTooLarge={identity} @@ -677,7 +677,7 @@ storiesOf('Internal/HighCharts/ChartTransformation', module) ]} config={{ type: 'treemap', - colors: fixtures.customPalette + colorPalette: fixtures.customPalette }} {...dataSet} onDataTooLarge={identity} @@ -696,7 +696,7 @@ storiesOf('Internal/HighCharts/ChartTransformation', module) }]} config={{ type: 'treemap', - colors: fixtures.customPalette + colorPalette: fixtures.customPalette }} {...dataSet} onDataTooLarge={identity} @@ -715,7 +715,7 @@ storiesOf('Internal/HighCharts/ChartTransformation', module) }]} config={{ type: 'treemap', - colors: fixtures.customPalette + colorPalette: fixtures.customPalette }} {...dataSet} onDataTooLarge={identity} @@ -764,7 +764,7 @@ storiesOf('Internal/HighCharts/ChartTransformation', module) position: 'left' }, legendLayout: 'horizontal', - colors: fixtures.customPalette + colorPalette: fixtures.customPalette }} {...dataSet} onDataTooLarge={identity} @@ -791,7 +791,7 @@ storiesOf('Internal/HighCharts/ChartTransformation', module) position: 'left' }, legendLayout: 'horizontal', - colors: fixtures.customPalette + colorPalette: fixtures.customPalette }} {...dataSet} onDataTooLarge={identity} @@ -818,7 +818,7 @@ storiesOf('Internal/HighCharts/ChartTransformation', module) position: 'left' }, legendLayout: 'horizontal', - colors: fixtures.customPalette + colorPalette: fixtures.customPalette }} {...dataSet} onDataTooLarge={identity} @@ -915,14 +915,21 @@ storiesOf('Internal/HighCharts/ChartTransformation', module) )}
)) - .add('Custom color pallete', () => ( + .add('Custom color palette', () => ( screenshotWrap( getChart({ dataSet: fixtures.barChartWith3MetricsAndViewByAttribute, - colors: [ - '#000000', - '#ff0000' - ] + colorPalette: [{ + guid: 'black', + fill: { + r: 0, g: 0, b: 0 + } + }, { + guid: 'red', + fill: { + r: 255, g: 0, b: 0 + } + }] }) ) )) @@ -1000,7 +1007,7 @@ storiesOf('Internal/HighCharts/ChartTransformation', module) position: 'top' }, legendLayout: 'vertical', - colors: fixtures.customPalette, + colorPalette: fixtures.customPalette, ...GERMAN_SEPARATORS }} {...dataSet} diff --git a/stories/internal/Drilldown.tsx b/stories/internal/Drilldown.tsx index c7dbcd35c8..7b378247eb 100644 --- a/stories/internal/Drilldown.tsx +++ b/stories/internal/Drilldown.tsx @@ -60,7 +60,7 @@ storiesOf('Internal/Drilldown', module) position: 'top' }, legendLayout: 'vertical', - colors: fixtures.customPalette + colorPalette: fixtures.customPalette }} {...dataSet} onDataTooLarge={noop} @@ -83,7 +83,7 @@ storiesOf('Internal/Drilldown', module) position: 'top' }, legendLayout: 'vertical', - colors: fixtures.customPalette + colorPalette: fixtures.customPalette }} {...dataSet} onDataTooLarge={noop} diff --git a/stories/test_data/fixtures.ts b/stories/test_data/fixtures.ts index 0280833dff..2536939a42 100644 --- a/stories/test_data/fixtures.ts +++ b/stories/test_data/fixtures.ts @@ -387,12 +387,42 @@ export const barChartWith6PreviousPeriodMeasures = (() => { })(); export const customPalette = [ - '#FF69B4', - '#d40606', - '#ee9c00', - '#e3ff00', - '#06bf00', - '#001a98' + { + guid: '01', + fill: { + r: 255, g: 105, b: 180 + } + }, + { + guid: '02', + fill: { + r: 212, g: 6, b: 6 + } + }, + { + guid: '03', + fill: { + r: 238, g: 156, b: 0 + } + }, + { + guid: '04', + fill: { + r: 227, g: 255, b: 0 + } + }, + { + guid: '05', + fill: { + r: 6, g: 191, b: 0 + } + }, + { + guid: '06', + fill: { + r: 0, g: 26, b: 152 + } + } ]; export const heatmapMetricRowColumn: any = {