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(partition): small multiples #1076

Merged
merged 31 commits into from
Mar 23, 2021
Merged
Show file tree
Hide file tree
Changes from 29 commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
b16daa0
feat: small multiples
monfera Mar 6, 2021
09e6d5a
test: mock update which is temporary
monfera Mar 11, 2021
dc5814e
test: mock update due to first part of margin fix ie text doesn't pro…
monfera Mar 11, 2021
bbbf7d8
fix: legend function post rebase fix
monfera Mar 11, 2021
62369dd
chore: old comment removal
monfera Mar 11, 2021
835b58a
fix: deactivate small multiples drilldown for now
monfera Mar 14, 2021
11a9ea3
feat: read inner breakdown direction from the spec
monfera Mar 14, 2021
f417693
feat: aspect ratio dependent inner panel zigzag
monfera Mar 14, 2021
55d4b2a
test: story mock update
monfera Mar 14, 2021
19881ad
fix: return nullShapeViewModel if there'd be nothing to return ie emp…
monfera Mar 14, 2021
473e50f
feat: fuller utilization of the space
monfera Mar 14, 2021
f1c0d89
test: knobs for layout
monfera Mar 15, 2021
7e8ce2b
feat: panel title
monfera Mar 15, 2021
e1e0e30
feat: separation of trees at multiplicative inner splot
monfera Mar 17, 2021
20348ae
feat: sort
monfera Mar 21, 2021
e240a93
chore: api update
monfera Mar 21, 2021
5693807
test: mock update
monfera Mar 21, 2021
fbdfcfc
test: changed mock for only sunburst
monfera Mar 21, 2021
a296549
feat: render panel title above the disk
monfera Mar 22, 2021
542f06f
feat: use inner margin from the small multiples spec
monfera Mar 22, 2021
dcf1e1a
chore: api doc improvs
monfera Mar 22, 2021
8987c66
fix: restored default inner pad
monfera Mar 22, 2021
6522be3
feat: using d3 scaleband padding conventions like xy
monfera Mar 22, 2021
883b840
feat: dedicate space for the panel title
monfera Mar 23, 2021
30e3241
chore: post rebase api gen
monfera Mar 23, 2021
5c1bbc2
refactor: new api convention for inner and outer padding
monfera Mar 23, 2021
b28d849
test: renamed test case
monfera Mar 23, 2021
5f2e3bb
chore: remove redundant check ht Marco
monfera Mar 23, 2021
cb12f05
fix: change the baseline for more robust vertical position ht Marco
monfera Mar 23, 2021
051c48b
Merge remote-tracking branch 'origin/master' into small-multiples-par…
monfera Mar 23, 2021
04062ad
chore: post-merge api update
monfera Mar 23, 2021
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
16 changes: 12 additions & 4 deletions .eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,17 @@ module.exports = {
: 0,
'import/namespace': process.env.NODE_ENV === 'production' ? 2 : 0,

/**
**************************************************************
* Rules that ensure sufficient freedom of expressing intent
**************************************************************
*/
'no-else-return': 'off',
'no-param-reassign': [1, { props: false }],
'@typescript-eslint/comma-spacing': 0,
'unicorn/no-nested-ternary': 0,
'@typescript-eslint/lines-between-class-members': ['error', 'always', { exceptAfterSingleLine: true }],

/**
*****************************************
* Rules to consider adding/fixing later
Expand All @@ -81,8 +92,6 @@ module.exports = {
'global-require': 1,
'import/no-dynamic-require': 1,
'no-shadow': 1,
'no-param-reassign': [1, { props: false }],
'@typescript-eslint/comma-spacing': 0,
'react/no-array-index-key': 1,
'react/prefer-stateless-function': 1,
'react/require-default-props': 'off',
Expand All @@ -92,7 +101,6 @@ module.exports = {
'jsx-a11y/click-events-have-key-events': 1,
'@typescript-eslint/member-ordering': 1,
eqeqeq: 1,
'unicorn/no-nested-ternary': 0,

/**
* Standard rules
Expand All @@ -107,7 +115,6 @@ module.exports = {
'no-bitwise': 0,
'no-void': 0,
yoda: 0,
'@typescript-eslint/lines-between-class-members': ['error', 'always', { exceptAfterSingleLine: true }],
'no-restricted-globals': 0,
'no-case-declarations': 0,
'no-return-await': 0,
Expand Down Expand Up @@ -255,6 +262,7 @@ module.exports = {
'unicorn/no-null': 0,
'unicorn/no-fn-reference-in-iterator': 0,
'unicorn/prefer-query-selector': 0,
'unicorn/prefer-array-find': 0,
'unicorn/no-for-loop': 0,
'unicorn/no-reduce': 0,
'unicorn/no-useless-undefined': 0,
Expand Down
2 changes: 1 addition & 1 deletion .playground/playground.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@

import React from 'react';

import { Example } from '../stories/wordcloud/1_wordcloud';
import { Example } from '../stories/small_multiples/7_sunbursts';

export class Playground extends React.Component {
render() {
Expand Down
30 changes: 20 additions & 10 deletions api/charts.api.md
Original file line number Diff line number Diff line change
Expand Up @@ -1680,6 +1680,9 @@ export type ProjectedValues = {
// @public
export type ProjectionClickListener = (values: ProjectedValues) => void;

// @public
export type Ratio = number;

// Warning: (ae-missing-release-tag) "RawTextGetter" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
//
// @public (undocumented)
Expand Down Expand Up @@ -1738,6 +1741,12 @@ export type RecursivePartial<T> = {
[P in keyof T]?: T[P] extends NonAny[] ? T[P] : T[P] extends ReadonlyArray<NonAny> ? T[P] : T[P] extends (infer U)[] ? RecursivePartial<U>[] : T[P] extends ReadonlyArray<infer U> ? ReadonlyArray<RecursivePartial<U>> : T[P] extends Set<infer V> ? Set<RecursivePartial<V>> : T[P] extends Map<infer K, infer V> ? Map<K, RecursivePartial<V>> : T[P] extends NonAny ? T[P] : RecursivePartial<T[P]>;
};

// @alpha
export type RelativeBandsPadding = {
outer: Ratio;
inner: Ratio;
};

// Warning: (ae-missing-release-tag) "RenderChangeListener" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
//
// @public
Expand Down Expand Up @@ -2036,19 +2045,20 @@ export interface SimplePadding {
export const SmallMultiples: React_2.FunctionComponent<SmallMultiplesProps>;

// @alpha (undocumented)
export type SmallMultiplesProps = Partial<Omit<SmallMultiplesSpec, 'id' | 'chatType' | 'specType'>>;
export type SmallMultiplesProps = Partial<Omit<SmallMultiplesSpec, 'chatType' | 'specType'>>;

// @alpha (undocumented)
export interface SmallMultiplesSpec extends Spec {
// (undocumented)
splitHorizontally?: string;
// (undocumented)
splitVertically?: string;
// (undocumented)
style?: {
verticalPanelPadding?: [number, number];
horizontalPanelPadding?: [number, number];
};
splitZigzag?: string;
style?: Partial<SmallMultiplesStyle>;
}

// @alpha
export interface SmallMultiplesStyle {
horizontalPanelPadding: RelativeBandsPadding;
verticalPanelPadding: RelativeBandsPadding;
}

// Warning: (ae-missing-release-tag) "SORT_INDEX_KEY" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
Expand Down Expand Up @@ -2455,8 +2465,8 @@ export type YDomainRange = YDomainBase & DomainRange & LogScaleOptions;
// src/chart_types/heatmap/layout/types/config_types.ts:29:13 - (ae-forgotten-export) The symbol "SizeRatio" needs to be exported by the entry point index.d.ts
// src/chart_types/heatmap/layout/types/config_types.ts:61:5 - (ae-forgotten-export) The symbol "TextAlign" needs to be exported by the entry point index.d.ts
// src/chart_types/heatmap/layout/types/config_types.ts:62:5 - (ae-forgotten-export) The symbol "TextBaseline" needs to be exported by the entry point index.d.ts
// src/chart_types/partition_chart/layout/types/config_types.ts:132:5 - (ae-forgotten-export) The symbol "TimeMs" needs to be exported by the entry point index.d.ts
// src/chart_types/partition_chart/layout/types/config_types.ts:133:5 - (ae-forgotten-export) The symbol "AnimKeyframe" needs to be exported by the entry point index.d.ts
// src/chart_types/partition_chart/layout/types/config_types.ts:139:5 - (ae-forgotten-export) The symbol "TimeMs" needs to be exported by the entry point index.d.ts
// src/chart_types/partition_chart/layout/types/config_types.ts:140:5 - (ae-forgotten-export) The symbol "AnimKeyframe" needs to be exported by the entry point index.d.ts

// (No @packageDocumentation comment for this package)

Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
6 changes: 3 additions & 3 deletions src/chart_types/goal_chart/state/selectors/geometries.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,13 +22,13 @@ import createCachedSelector from 're-reselect';
import { ChartTypes } from '../../..';
import { SpecTypes } from '../../../../specs/constants';
import { GlobalChartState } from '../../../../state/chart_state';
import { getChartIdSelector } from '../../../../state/selectors/get_chart_id';
import { getSpecs } from '../../../../state/selectors/get_settings_specs';
import { getSpecsFromStore } from '../../../../state/utils';
import { nullShapeViewModel, ShapeViewModel } from '../../layout/types/viewmodel_types';
import { GoalSpec } from '../../specs';
import { render } from './scenegraph';

const getSpecs = (state: GlobalChartState) => state.specs;

const getParentDimensions = (state: GlobalChartState) => state.parentDimensions;

/** @internal */
Expand All @@ -38,4 +38,4 @@ export const geometries = createCachedSelector(
const goalSpecs = getSpecsFromStore<GoalSpec>(specs, ChartTypes.Goal, SpecTypes.Series);
return goalSpecs.length === 1 ? render(goalSpecs[0], parentDimensions) : nullShapeViewModel();
},
)((state) => state.chartId);
)(getChartIdSelector);
5 changes: 3 additions & 2 deletions src/chart_types/goal_chart/state/selectors/picked_shapes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import createCachedSelector from 're-reselect';

import { LayerValue } from '../../../../specs';
import { GlobalChartState } from '../../../../state/chart_state';
import { getChartIdSelector } from '../../../../state/selectors/get_chart_id';
import { BulletViewModel } from '../../layout/types/viewmodel_types';
import { geometries } from './geometries';

Expand All @@ -38,7 +39,7 @@ export const getPickedShapes = createCachedSelector(
const y = pointerPosition.y - chartCenter.y;
return picker(x, y);
},
)((state) => state.chartId);
)(getChartIdSelector);

/** @internal */
export const getPickedShapesLayerValues = createCachedSelector(
Expand All @@ -57,4 +58,4 @@ export const getPickedShapesLayerValues = createCachedSelector(
});
return elements;
},
)((state) => state.chartId);
)(getChartIdSelector);
3 changes: 2 additions & 1 deletion src/chart_types/goal_chart/state/selectors/tooltip.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
import createCachedSelector from 're-reselect';

import { TooltipInfo } from '../../../../components/tooltip/types';
import { getChartIdSelector } from '../../../../state/selectors/get_chart_id';
import { getSpecOrNull } from './goal_spec';
import { getPickedShapes } from './picked_shapes';

Expand Down Expand Up @@ -58,4 +59,4 @@ export const getTooltipInfoSelector = createCachedSelector(

return tooltipInfo;
},
)((state) => state.chartId);
)(getChartIdSelector);
2 changes: 1 addition & 1 deletion src/chart_types/heatmap/specs/heatmap.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
import React from 'react';

import { ChartTypes } from '../..';
import { Predicate } from '../../../common/predicate';
import { ScaleType } from '../../../scales/constants';
import { SeriesScales, Spec } from '../../../specs';
import { SpecTypes } from '../../../specs/constants';
Expand All @@ -28,7 +29,6 @@ import { Accessor, AccessorFn } from '../../../utils/accessor';
import { Color, Datum, RecursivePartial } from '../../../utils/common';
import { config } from '../layout/config/config';
import { Config } from '../layout/types/config_types';
import { Predicate } from '../utils/common';

const defaultProps = {
chartType: ChartTypes.Heatmap,
Expand Down
4 changes: 1 addition & 3 deletions src/chart_types/heatmap/state/selectors/get_heatmap_spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,13 +20,11 @@ import createCachedSelector from 're-reselect';

import { ChartTypes } from '../../..';
import { SpecTypes } from '../../../../specs';
import { GlobalChartState } from '../../../../state/chart_state';
import { getChartIdSelector } from '../../../../state/selectors/get_chart_id';
import { getSpecs } from '../../../../state/selectors/get_settings_specs';
import { getSpecsFromStore } from '../../../../state/utils';
import { HeatmapSpec } from '../../specs';

const getSpecs = (state: GlobalChartState) => state.specs;

/** @internal */
export const getHeatmapSpecSelector = createCachedSelector([getSpecs], (specs) => {
const spec = getSpecsFromStore<HeatmapSpec>(specs, ChartTypes.Heatmap, SpecTypes.Series);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,12 @@
*/
import createCachedSelector from 're-reselect';

import { getPredicateFn } from '../../../../common/predicate';
import { ScaleType } from '../../../../scales/constants';
import { getChartIdSelector } from '../../../../state/selectors/get_chart_id';
import { getSettingsSpecSelector } from '../../../../state/selectors/get_settings_specs';
import { getAccessorValue } from '../../../../utils/accessor';
import { mergeXDomain } from '../../../xy_chart/domains/x_domain';
import { getPredicateFn } from '../../utils/common';
import { HeatmapTable } from './compute_chart_dimensions';
import { getHeatmapSpecSelector } from './get_heatmap_spec';

Expand Down
9 changes: 8 additions & 1 deletion src/chart_types/partition_chart/layout/types/config_types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -79,12 +79,19 @@ export interface FillFontSizeRange {
maximizeFontSize: boolean;
}

export interface RelativeMargins {
left: SizeRatio;
right: SizeRatio;
top: SizeRatio;
bottom: SizeRatio;
}

// todo switch to `io-ts` style, generic way of combining static and runtime type info
export interface StaticConfig extends FillFontSizeRange {
// shape geometry
width: number;
height: number;
margin: { left: SizeRatio; right: SizeRatio; top: SizeRatio; bottom: SizeRatio };
margin: RelativeMargins;
emptySizeRatio: SizeRatio;
outerSizeRatio: SizeRatio;
clockwiseSectors: boolean;
Expand Down
46 changes: 42 additions & 4 deletions src/chart_types/partition_chart/layout/types/viewmodel_types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import {
PointTuple,
PointTuples,
Radian,
SizeRatio,
} from '../../../../common/geometry';
import { Font, VerticalAlignments } from '../../../../common/text_utils';
import { LegendPath } from '../../../../state/actions/legend';
Expand All @@ -35,7 +36,7 @@ import { Layer } from '../../specs';
import { config, MODEL_KEY, ValueGetterName } from '../config';
import { ArrayNode, HierarchyOfArrays } from '../utils/group_by_rollup';
import { LinkLabelsViewModelSpec } from '../viewmodel/link_text_layout';
import { Config } from './config_types';
import { Config, PartitionLayout } from './config_types';

/** @internal */
export type LinkLabelVM = {
Expand Down Expand Up @@ -88,7 +89,13 @@ export interface RowSet {
}

/** @internal */
export interface QuadViewModel extends ShapeTreeNode {
export interface SmallMultiplesIndices {
index: number;
innerIndex: number;
}

/** @internal */
export interface QuadViewModel extends ShapeTreeNode, SmallMultiplesIndices {
strokeWidth: number;
strokeStyle: string;
fillColor: string;
Expand All @@ -104,7 +111,21 @@ export interface OutsideLinksViewModel {
export type PickFunction = (x: Pixels, y: Pixels, focus: ContinuousDomainFocus) => Array<QuadViewModel>;

/** @internal */
export type ShapeViewModel = {
export interface PartitionSmallMultiplesModel extends SmallMultiplesIndices {
panelTitle: string;
partitionLayout: PartitionLayout;
top: SizeRatio;
left: SizeRatio;
width: SizeRatio;
height: SizeRatio;
innerRowCount: number;
innerColumnCount: number;
innerRowIndex: number;
innerColumnIndex: number;
}

/** @internal */
export interface ShapeViewModel extends PartitionSmallMultiplesModel {
config: Config;
layers: Layer[];
quadViewModel: QuadViewModel[];
Expand All @@ -114,7 +135,7 @@ export type ShapeViewModel = {
diskCenter: PointObject;
pickQuads: PickFunction;
outerRadius: number;
};
}

const defaultFont: Font = {
fontStyle: 'normal',
Expand All @@ -125,8 +146,25 @@ const defaultFont: Font = {
textOpacity: 1,
};

/** @internal */
export const nullPartitionSmallMultiplesModel = (partitionLayout: PartitionLayout): PartitionSmallMultiplesModel => ({
index: 0,
innerIndex: 0,
panelTitle: '',
top: 0,
left: 0,
width: 0,
height: 0,
innerRowCount: 0,
innerColumnCount: 0,
innerRowIndex: 0,
innerColumnIndex: 0,
partitionLayout,
});

/** @internal */
export const nullShapeViewModel = (specifiedConfig?: Config, diskCenter?: PointObject): ShapeViewModel => ({
...nullPartitionSmallMultiplesModel((specifiedConfig || config).partitionLayout),
config: specifiedConfig || config,
layers: [],
quadViewModel: [],
Expand Down
13 changes: 3 additions & 10 deletions src/chart_types/partition_chart/layout/viewmodel/picked_shapes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,17 +27,10 @@ import { AGGREGATE_KEY, DEPTH_KEY, getNodeName, PARENT_KEY, PATH_KEY, SORT_INDEX
/** @internal */
export const pickedShapes = (
models: ShapeViewModel[],
pointerPosition: Point,
{ x, y }: Point,
foci: ContinuousDomainFocus[],
): QuadViewModel[] => {
const geoms = models[0];
const focus = foci[0];
const picker = geoms.pickQuads;
const { diskCenter } = geoms;
const x = pointerPosition.x - diskCenter.x;
const y = pointerPosition.y - diskCenter.y;
return picker(x, y, focus);
};
): QuadViewModel[] =>
models.flatMap(({ diskCenter, pickQuads }) => pickQuads(x - diskCenter.x, y - diskCenter.y, foci[0]));

/** @internal */
export function pickShapesLayerValues(shapes: QuadViewModel[]): LayerValue[][] {
Expand Down
Loading