Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(bar_chart): color overrides #271

Merged
merged 6 commits into from
Aug 5, 2019
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/chart_types/xy_chart/domains/y_domain.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ export type YDomain = BaseDomain & {
};
export type YBasicSeriesSpec = Pick<
BasicSeriesSpec,
'id' | 'seriesType' | 'yScaleType' | 'groupId' | 'stackAccessors' | 'yScaleToDataExtent' | 'colorAccessors'
'id' | 'seriesType' | 'yScaleType' | 'groupId' | 'stackAccessors' | 'yScaleToDataExtent' | 'styleAccessor'
> & { stackAsPercentage?: boolean };

export function mergeYDomain(
Expand Down
118 changes: 117 additions & 1 deletion src/chart_types/xy_chart/rendering/rendering.test.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,16 @@
import { DEFAULT_GEOMETRY_STYLES } from '../../../utils/themes/theme_commons';
import { getSpecId } from '../../../utils/ids';
import { BarGeometry, getGeometryStyle, isPointOnGeometry, PointGeometry } from './rendering';
import {
BarGeometry,
getGeometryStyle,
isPointOnGeometry,
PointGeometry,
getStyleOverrides,
GeometryId,
} from './rendering';
import { BarSeriesStyle } from '../../../utils/themes/theme';
import { DataSeriesDatum } from '../utils/series';
import { RecursivePartial, mergePartial } from '../../../utils/commons';

describe('Rendering utils', () => {
test('check if point is in geometry', () => {
Expand Down Expand Up @@ -168,4 +178,110 @@ describe('Rendering utils', () => {

expect(noHover).toEqual({ opacity: 1 });
});

describe('getStyleOverrides', () => {
let mockAccessor: jest.Mock;

const sampleSeriesStyle: BarSeriesStyle = {
rect: {
opacity: 1,
},
rectBorder: {
visible: true,
strokeWidth: 1,
},
displayValue: {
fontSize: 10,
fontFamily: 'helvetica',
fill: 'blue',
padding: 1,
offsetX: 1,
offsetY: 1,
},
};
const datum: DataSeriesDatum = {
x: 1,
y1: 2,
y0: 3,
initialY1: 4,
initialY0: 5,
};
const geometryId: GeometryId = {
specId: getSpecId('test'),
seriesKey: ['test'],
};

beforeEach(() => {
mockAccessor = jest.fn();
});

it('should return input seriesStyle if styleAccessor is null', () => {
const styleOverrides = getStyleOverrides(null, datum, geometryId, sampleSeriesStyle);

expect(styleOverrides).toBe(sampleSeriesStyle);
});

it('should return input seriesStyle if styleAccessor returns null', () => {
mockAccessor.mockReturnValue(null);
const styleOverrides = getStyleOverrides(mockAccessor, datum, geometryId, sampleSeriesStyle);

expect(styleOverrides).toBe(sampleSeriesStyle);
});

it('should call styleAccessor with datum and geometryId', () => {
getStyleOverrides(mockAccessor, datum, geometryId, sampleSeriesStyle);

expect(mockAccessor).toBeCalledWith(datum, geometryId);
});

it('should return seriesStyle with updated fill color', () => {
const color = 'blue';
mockAccessor.mockReturnValue(color);
const styleOverrides = getStyleOverrides(mockAccessor, datum, geometryId, sampleSeriesStyle);
const expectedStyles: BarSeriesStyle = {
...sampleSeriesStyle,
rect: {
...sampleSeriesStyle.rect,
fill: color,
},
};
expect(styleOverrides).toEqual(expectedStyles);
});

it('should return a new seriesStyle object with color', () => {
mockAccessor.mockReturnValue('blue');
const styleOverrides = getStyleOverrides(mockAccessor, datum, geometryId, sampleSeriesStyle);

expect(styleOverrides).not.toBe(sampleSeriesStyle);
});

it('should return seriesStyle with updated partial style', () => {
const partialStyle: RecursivePartial<BarSeriesStyle> = {
rect: {
fill: 'blue',
},
rectBorder: {
strokeWidth: 10,
},
};
mockAccessor.mockReturnValue(partialStyle);
const styleOverrides = getStyleOverrides(mockAccessor, datum, geometryId, sampleSeriesStyle);
const expectedStyles = mergePartial(sampleSeriesStyle, partialStyle, {
mergeOptionalPartialValues: true,
});

expect(styleOverrides).toEqual(expectedStyles);
});

it('should return a new seriesStyle object with partial styles', () => {
mockAccessor.mockReturnValue({
rect: {
fill: 'blue',
},
});
const styleOverrides = getStyleOverrides(mockAccessor, datum, geometryId, sampleSeriesStyle);

expect(styleOverrides).not.toBe(sampleSeriesStyle);
});
});
});
50 changes: 42 additions & 8 deletions src/chart_types/xy_chart/rendering/rendering.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { area, line } from 'd3-shape';

import { CanvasTextBBoxCalculator } from '../../../utils/bbox/canvas_text_bbox_calculator';
import {
AreaSeriesStyle,
Expand All @@ -16,7 +17,8 @@ import { CurveType, getCurveFactory } from '../../../utils/curves';
import { LegendItem } from '../legend/legend';
import { DataSeriesDatum } from '../utils/series';
import { belongsToDataSeries } from '../utils/series_utils';
import { DisplayValueSpec } from '../utils/specs';
import { DisplayValueSpec, StyleAccessor } from '../utils/specs';
import { mergePartial } from '../../../utils/commons';

export interface GeometryId {
specId: SpecId;
Expand Down Expand Up @@ -113,6 +115,33 @@ export function mutableIndexedGeometryMapUpsert(
}
}

export function getStyleOverrides(
styleAccessor: StyleAccessor | null = null,
markov00 marked this conversation as resolved.
Show resolved Hide resolved
datum: DataSeriesDatum,
geometryId: GeometryId,
seriesStyle: BarSeriesStyle,
): BarSeriesStyle {
const styleOverride = styleAccessor && styleAccessor(datum, geometryId);

if (styleOverride) {
markov00 marked this conversation as resolved.
Show resolved Hide resolved
if (typeof styleOverride === 'string') {
return {
...seriesStyle,
rect: {
...seriesStyle.rect,
fill: styleOverride,
},
};
} else {
seriesStyle = mergePartial(seriesStyle, styleOverride, {
mergeOptionalPartialValues: true,
});
}
}

return seriesStyle;
}

export function renderPoints(
shift: number,
dataset: DataSeriesDatum[],
Expand Down Expand Up @@ -195,8 +224,9 @@ export function renderBars(
color: string,
specId: SpecId,
seriesKey: any[],
seriesStyle: BarSeriesStyle,
sharedSeriesStyle: BarSeriesStyle,
displayValueSettings?: DisplayValueSpec,
styleAccessor?: StyleAccessor,
): {
barGeometries: BarGeometry[];
indexedGeometries: Map<any, IndexedGeometry[]>;
Expand All @@ -210,8 +240,8 @@ export function renderBars(

// default padding to 1 for now
const padding = 1;
const fontSize = seriesStyle.displayValue.fontSize;
const fontFamily = seriesStyle.displayValue.fontFamily;
const fontSize = sharedSeriesStyle.displayValue.fontSize;
const fontFamily = sharedSeriesStyle.displayValue.fontFamily;

dataset.forEach((datum) => {
const { y0, y1, initialY1 } = datum;
Expand Down Expand Up @@ -278,6 +308,13 @@ export function renderBars(
}
: undefined;

const geometryId = {
specId,
seriesKey,
};

const seriesStyle = getStyleOverrides(styleAccessor, datum, geometryId, sharedSeriesStyle);

const barGeometry: BarGeometry = {
displayValue,
x,
Expand All @@ -290,10 +327,7 @@ export function renderBars(
y: initialY1,
accessor: 'y1',
},
geometryId: {
specId,
seriesKey,
},
geometryId,
seriesStyle,
};
mutableIndexedGeometryMapUpsert(indexedGeometries, datum.x, barGeometry);
Expand Down
1 change: 1 addition & 0 deletions src/chart_types/xy_chart/store/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -451,6 +451,7 @@ export function renderGeometries(
ds.key,
barSeriesStyle,
displayValueSettings,
spec.styleAccessor,
);
barGeometriesIndex = mergeGeometriesIndexes(barGeometriesIndex, renderedBars.indexedGeometries);
bars.push(...renderedBars.barGeometries);
Expand Down
9 changes: 4 additions & 5 deletions src/chart_types/xy_chart/utils/series.ts
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,6 @@ export function splitSeries(
xValues: Set<any>;
} {
const { xAccessor, yAccessors, y0Accessors, splitSeriesAccessors = [] } = accessors;
const colorAccessors = accessors.colorAccessors ? accessors.colorAccessors : splitSeriesAccessors;
const isMultipleY = yAccessors && yAccessors.length > 1;
const series = new Map<string, RawDataSeries>();
const colorsValues = new Map<string, any[]>();
Expand All @@ -102,15 +101,15 @@ export function splitSeries(
const seriesKey = getAccessorsValues(datum, splitSeriesAccessors);
if (isMultipleY) {
yAccessors.forEach((accessor, index) => {
const colorValues = getColorValues(datum, colorAccessors, accessor);
const colorValues = getColorValues(datum, splitSeriesAccessors, accessor);
const colorValuesKey = getColorValuesAsString(colorValues, specId);
colorsValues.set(colorValuesKey, colorValues);
const cleanedDatum = cleanDatum(datum, xAccessor, accessor, y0Accessors && y0Accessors[index]);
xValues.add(cleanedDatum.x);
updateSeriesMap(series, [...seriesKey, accessor], cleanedDatum, specId, colorValuesKey);
}, {});
} else {
const colorValues = getColorValues(datum, colorAccessors);
const colorValues = getColorValues(datum, splitSeriesAccessors);
const colorValuesKey = getColorValuesAsString(colorValues, specId);
colorsValues.set(colorValuesKey, colorValues);
const cleanedDatum = cleanDatum(datum, xAccessor, yAccessors[0], y0Accessors && y0Accessors[0]);
Expand Down Expand Up @@ -165,8 +164,8 @@ function getAccessorsValues(datum: Datum, accessors: Accessor[] = []): any[] {
/**
* Get the array of values that forms a series key
*/
function getColorValues(datum: Datum, colorAccessors: Accessor[] = [], yAccessorValue?: any): any[] {
const colorValues = getAccessorsValues(datum, colorAccessors);
function getColorValues(datum: Datum, accessors: Accessor[] = [], yAccessorValue?: any): any[] {
const colorValues = getAccessorsValues(datum, accessors);
if (yAccessorValue) {
return [...colorValues, yAccessorValue];
}
Expand Down
8 changes: 6 additions & 2 deletions src/chart_types/xy_chart/utils/specs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,15 @@ import { Omit, RecursivePartial } from '../../../utils/commons';
import { AnnotationId, AxisId, GroupId, SpecId } from '../../../utils/ids';
import { ScaleContinuousType, ScaleType } from '../../../utils/scales/scales';
import { CurveType } from '../../../utils/curves';
import { DataSeriesColorsValues } from './series';
import { DataSeriesColorsValues, RawDataSeriesDatum } from './series';
import { GeometryId } from '../rendering/rendering';

export type Datum = any;
export type Rotation = 0 | 90 | -90 | 180;
export type Rendering = 'canvas' | 'svg';
export type Color = string;
export type StyleOverride = RecursivePartial<BarSeriesStyle> | Color | null;
export type StyleAccessor = (datum: RawDataSeriesDatum, geometryId: GeometryId) => StyleOverride;

interface DomainMinInterval {
/** Custom minInterval for the domain which will affect data bucket size.
Expand Down Expand Up @@ -97,7 +101,7 @@ export interface SeriesAccessors {
/** An array of fields thats indicates the stack membership */
stackAccessors?: Accessor[];
/** An optional array of field name thats indicates the stack membership */
markov00 marked this conversation as resolved.
Show resolved Hide resolved
colorAccessors?: Accessor[];
styleAccessor?: StyleAccessor;
}

export interface SeriesScales {
Expand Down
Loading