Skip to content

Commit

Permalink
feat(wordcloud): click and over events on text (#1180)
Browse files Browse the repository at this point in the history
The `<Worldcloud>` chart now fully support the `onElementClick`, `onElementOver` and `onElementOut` events, returning the original datum the callback.

close #1156
  • Loading branch information
markov00 authored Jun 3, 2021
1 parent a64f333 commit 196fb6a
Show file tree
Hide file tree
Showing 12 changed files with 182 additions and 77 deletions.
71 changes: 62 additions & 9 deletions api/charts.api.md
Original file line number Diff line number Diff line change
Expand Up @@ -678,10 +678,10 @@ export type DisplayValueStyle = Omit<TextStyle, 'fill' | 'fontSize'> & {
export type DomainRange = LowerBoundedDomain | UpperBoundedDomain | CompleteBoundedDomain | UnboundedDomainWithInterval;

// @public (undocumented)
export type ElementClickListener = (elements: Array<XYChartElementEvent | PartitionElementEvent | HeatmapElementEvent>) => void;
export type ElementClickListener = (elements: Array<XYChartElementEvent | PartitionElementEvent | HeatmapElementEvent | WordCloudElementEvent>) => void;

// @public (undocumented)
export type ElementOverListener = (elements: Array<XYChartElementEvent | PartitionElementEvent | HeatmapElementEvent>) => void;
export type ElementOverListener = (elements: Array<XYChartElementEvent | PartitionElementEvent | HeatmapElementEvent | WordCloudElementEvent>) => void;

// @public (undocumented)
export const entryKey: ([key]: ArrayEntry) => string;
Expand Down Expand Up @@ -1330,6 +1330,9 @@ export interface OrderBy {
// @public (undocumented)
export type OrdinalDomain = (number | string)[];

// @public (undocumented)
export type OutOfRoomCallback = (wordCount: number, renderedWordCount: number, renderedWords: string[]) => void;

// Warning: (ae-forgotten-export) The symbol "PerSideDistance" needs to be exported by the entry point index.d.ts
//
// @public (undocumented)
Expand Down Expand Up @@ -2114,22 +2117,66 @@ export interface Visible {
visible: boolean;
}

// @public (undocumented)
export const WeightFn: Readonly<{
log: "log";
linear: "linear";
exponential: "exponential";
squareRoot: "squareRoot";
}>;

// @public (undocumented)
export type WeightFn = $Values<typeof WeightFn>;

// Warning: (ae-forgotten-export) The symbol "SpecRequiredProps" needs to be exported by the entry point index.d.ts
// Warning: (ae-forgotten-export) The symbol "SpecOptionalProps" needs to be exported by the entry point index.d.ts
//
// @alpha (undocumented)
export const Wordcloud: React_2.FunctionComponent<SpecRequiredProps_9 & SpecOptionalProps_9>;

// @public (undocumented)
export interface WordcloudConfigs {
// (undocumented)
count: number;
// (undocumented)
endAngle: number;
// (undocumented)
exponent: number;
// (undocumented)
fontFamily: string;
// (undocumented)
fontStyle: string;
// (undocumented)
fontWeight: number;
// (undocumented)
height: number;
// (undocumented)
maxFontSize: number;
// (undocumented)
minFontSize: number;
// (undocumented)
padding: number;
// (undocumented)
spiral: string;
// (undocumented)
startAngle: number;
// (undocumented)
weightFn: WeightFn;
// (undocumented)
width: number;
}

// @public (undocumented)
export type WordCloudElementEvent = [WordModel, SeriesIdentifier];

// @alpha (undocumented)
export interface WordcloudSpec extends Spec {
// (undocumented)
angleCount: number;
// (undocumented)
chartType: typeof ChartType.Wordcloud;
// (undocumented)
config: RecursivePartial<PartitionConfig>;
// Warning: (ae-forgotten-export) The symbol "WordModel" needs to be exported by the entry point index.d.ts
//
config: RecursivePartial<WordcloudConfigs>;
// (undocumented)
data: WordModel[];
// (undocumented)
Expand All @@ -2146,8 +2193,6 @@ export interface WordcloudSpec extends Spec {
maxFontSize: number;
// (undocumented)
minFontSize: number;
// Warning: (ae-forgotten-export) The symbol "OutOfRoomCallback" needs to be exported by the entry point index.d.ts
//
// (undocumented)
outOfRoomCallback: OutOfRoomCallback;
// (undocumented)
Expand All @@ -2158,12 +2203,20 @@ export interface WordcloudSpec extends Spec {
spiral: string;
// (undocumented)
startAngle: number;
// Warning: (ae-forgotten-export) The symbol "WeightFn" needs to be exported by the entry point index.d.ts
//
// (undocumented)
weightFn: WeightFn;
}

// @public (undocumented)
export interface WordModel {
// (undocumented)
color: Color;
// (undocumented)
text: string;
// (undocumented)
weight: number;
}

// @public (undocumented)
export type XScaleType = typeof ScaleType.Ordinal | ScaleContinuousType;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import {
HeatmapElementEvent,
LayerValue,
PartitionElementEvent,
WordCloudElementEvent,
XYChartElementEvent,
} from '../../../../specs/settings';
import { onMouseDown, onMouseUp, onPointerMove } from '../../../../state/actions/mouse';
Expand Down Expand Up @@ -68,7 +69,7 @@ describe.each([
let store: Store<GlobalChartState>;
let onClickListener: jest.Mock<
undefined,
Array<(XYChartElementEvent | PartitionElementEvent | HeatmapElementEvent)[]>
Array<(XYChartElementEvent | PartitionElementEvent | HeatmapElementEvent | WordCloudElementEvent)[]>
>;
let debugState: DebugState;

Expand Down Expand Up @@ -113,7 +114,10 @@ describe.each([

function expectCorrectClickInfo(
store: Store<GlobalChartState>,
onClickListener: jest.Mock<undefined, Array<(XYChartElementEvent | PartitionElementEvent | HeatmapElementEvent)[]>>,
onClickListener: jest.Mock<
undefined,
Array<(XYChartElementEvent | PartitionElementEvent | HeatmapElementEvent | WordCloudElementEvent)[]>
>,
partition: SinglePartitionDebugState,
index: number,
) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ import {
HeatmapElementEvent,
GroupBySpec,
SmallMultiplesSpec,
WordCloudElementEvent,
} from '../../../../specs';
import { updateParentDimensions } from '../../../../state/actions/chart_settings';
import { onMouseDown, onMouseUp, onPointerMove } from '../../../../state/actions/mouse';
Expand Down Expand Up @@ -101,7 +102,7 @@ describe('Picked shapes selector', () => {
test('treemap check picked geometries', () => {
const onClickListener = jest.fn<
undefined,
Array<(XYChartElementEvent | PartitionElementEvent | HeatmapElementEvent)[]>
Array<XYChartElementEvent | PartitionElementEvent | HeatmapElementEvent | WordCloudElementEvent>[]
>((): undefined => undefined);
addSeries(store, treemapSpec, {
onElementClick: onClickListener,
Expand Down Expand Up @@ -154,7 +155,7 @@ describe('Picked shapes selector', () => {
test('small multiples pie chart check picked geometries', () => {
const onClickListener = jest.fn<
undefined,
Array<(XYChartElementEvent | PartitionElementEvent | HeatmapElementEvent)[]>
Array<XYChartElementEvent | PartitionElementEvent | HeatmapElementEvent | WordCloudElementEvent>[]
>((): undefined => undefined);
addSmallMultiplesSeries(
store,
Expand Down Expand Up @@ -222,7 +223,7 @@ describe('Picked shapes selector', () => {
test('sunburst check picked geometries', () => {
const onClickListener = jest.fn<
undefined,
Array<(XYChartElementEvent | PartitionElementEvent | HeatmapElementEvent)[]>
Array<XYChartElementEvent | PartitionElementEvent | HeatmapElementEvent | WordCloudElementEvent>[]
>((): undefined => undefined);
addSeries(store, sunburstSpec, {
onElementClick: onClickListener,
Expand Down
5 changes: 4 additions & 1 deletion src/chart_types/wordcloud/layout/types/viewmodel_types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -64,9 +64,10 @@ export interface Word {
y0: number;
y1: number;
yoff: number;
datum: WordModel;
}

/** @internal */
/** @public */
export interface Configs {
count: number;
endAngle: number;
Expand Down Expand Up @@ -122,6 +123,7 @@ export type ShapeViewModel = {
wordcloudViewModel: WordcloudViewModel;
chartCenter: PointObject;
pickQuads: PickFunction;
specId: string;
};

const commonDefaults: WordcloudViewModel = {
Expand Down Expand Up @@ -158,4 +160,5 @@ export const nullShapeViewModel = (specifiedConfig?: Config, chartCenter?: Point
wordcloudViewModel: nullWordcloudViewModel,
chartCenter: chartCenter || { x: 0, y: 0 },
pickQuads: () => [],
specId: 'empty',
});
2 changes: 2 additions & 0 deletions src/chart_types/wordcloud/layout/viewmodel/viewmodel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ export function shapeViewModel(spec: WordcloudSpec, config: Config): ShapeViewMo
};

const {
id,
startAngle,
endAngle,
angleCount,
Expand Down Expand Up @@ -78,5 +79,6 @@ export function shapeViewModel(spec: WordcloudSpec, config: Config): ShapeViewMo
chartCenter,
wordcloudViewModel,
pickQuads,
specId: id,
};
}
104 changes: 78 additions & 26 deletions src/chart_types/wordcloud/renderer/svg/connected_component.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import { connect } from 'react-redux';
import { bindActionCreators, Dispatch } from 'redux';

import { ScreenReaderSummary } from '../../../../components/accessibility';
import { SettingsSpec, WordCloudElementEvent } from '../../../../specs/settings';
import { onChartRendered } from '../../../../state/actions/chart';
import { GlobalChartState } from '../../../../state/chart_state';
import {
Expand All @@ -32,6 +33,7 @@ import {
getA11ySettingsSelector,
} from '../../../../state/selectors/get_accessibility_config';
import { getInternalIsInitializedSelector, InitStatus } from '../../../../state/selectors/get_internal_is_intialized';
import { getSettingsSpecSelector } from '../../../../state/selectors/get_settings_specs';
import { Dimensions } from '../../../../utils/dimensions';
import { Configs, Datum, nullShapeViewModel, ShapeViewModel, Word } from '../../layout/types/viewmodel_types';
import { geometries } from '../../state/selectors/geometries';
Expand Down Expand Up @@ -104,6 +106,7 @@ function layoutMaker(config: Configs, data: Datum[]) {
const words = data.map((d) => {
const weightFn = weightFnLookup[config.weightFn];
return {
datum: d,
text: d.text,
color: d.color,
fontFamily: config.fontFamily,
Expand All @@ -125,36 +128,74 @@ function layoutMaker(config: Configs, data: Datum[]) {
.fontSize((d: Word) => getFontSize(d));
}

const View = ({ words, conf }: { words: Word[]; conf: Configs }) => (
<svg width={getWidth(conf)} height={getHeight(conf)} role="presentation">
<g transform={`translate(${getWidth(conf) / 2}, ${getHeight(conf) / 2})`}>
{words.map((d, i) => {
return (
<text
key={String(i)}
style={{
fontSize: getFontSize(d),
fontStyle: getFontStyle(d),
fontFamily: getFont(d),
fontWeight: getFontWeight(d),
fill: d.color,
}}
textAnchor="middle"
transform={`translate(${d.x}, ${d.y}) rotate(${d.rotate})`}
>
{d.text}
</text>
);
})}
</g>
</svg>
);
const View = ({
words,
conf,
actions: { onElementClick, onElementOver, onElementOut },
specId,
}: {
words: Word[];
conf: Configs;
actions: {
onElementClick?: SettingsSpec['onElementClick'];
onElementOver?: SettingsSpec['onElementOver'];
onElementOut?: SettingsSpec['onElementOut'];
};
specId: string;
}) => {
return (
<svg width={getWidth(conf)} height={getHeight(conf)} role="presentation">
<g transform={`translate(${getWidth(conf) / 2}, ${getHeight(conf) / 2})`}>
{words.map((d, i) => {
const elements: WordCloudElementEvent[] = [[d.datum, { specId, key: specId }]];
const actions = {
...(onElementClick && {
onClick: () => {
onElementClick(elements);
},
}),
...(onElementOver && {
onMouseOver: () => {
onElementOver(elements);
},
}),
...(onElementOut && {
onMouseOut: () => {
onElementOut();
},
}),
};
return (
<text
key={String(i)}
style={{
fontSize: getFontSize(d),
fontStyle: getFontStyle(d),
fontFamily: getFont(d),
fontWeight: getFontWeight(d),
fill: d.color,
}}
textAnchor="middle"
transform={`translate(${d.x}, ${d.y}) rotate(${d.rotate})`}
{...actions}
>
{d.text}
</text>
);
})}
</g>
</svg>
);
};

interface ReactiveChartStateProps {
initialized: boolean;
geometries: ShapeViewModel;
chartContainerDimensions: Dimensions;
a11ySettings: A11ySettings;
onElementClick?: SettingsSpec['onElementClick'];
onElementOver?: SettingsSpec['onElementOver'];
onElementOut?: SettingsSpec['onElementOut'];
}

interface ReactiveChartDispatchProps {
Expand Down Expand Up @@ -182,8 +223,11 @@ class Component extends React.Component<Props> {
const {
initialized,
chartContainerDimensions: { width, height },
geometries: { wordcloudViewModel },
geometries: { wordcloudViewModel, specId },
a11ySettings,
onElementClick,
onElementOver,
onElementOut,
} = this.props;
if (!initialized || width === 0 || height === 0) {
return null;
Expand Down Expand Up @@ -224,7 +268,12 @@ class Component extends React.Component<Props> {

return (
<figure aria-labelledby={a11ySettings.labelId} aria-describedby={a11ySettings.descriptionId}>
<View words={renderedWordObjects} conf={conf1} />
<View
words={renderedWordObjects}
conf={conf1}
actions={{ onElementClick, onElementOut, onElementOver }}
specId={specId}
/>
<ScreenReaderSummary />
</figure>
);
Expand Down Expand Up @@ -260,6 +309,9 @@ const mapStateToProps = (state: GlobalChartState): ReactiveChartStateProps => {
geometries: geometries(state),
chartContainerDimensions: state.parentDimensions,
a11ySettings: getA11ySettingsSelector(state),
onElementClick: getSettingsSpecSelector(state).onElementClick,
onElementOver: getSettingsSpecSelector(state).onElementOver,
onElementOut: getSettingsSpecSelector(state).onElementOut,
};
};

Expand Down
Loading

0 comments on commit 196fb6a

Please sign in to comment.