Skip to content

Commit

Permalink
feat(tooltip): improve positioning with popperjs (opensearch-project#651
Browse files Browse the repository at this point in the history
)

- configurable placement
- configurable fallback placement
- configurable tooltip boundary element
- improved placement options
- custom tooltip component

related to opensearch-project#596
  • Loading branch information
nickofthyme authored May 28, 2020
1 parent 422c33c commit 61d1d9a
Show file tree
Hide file tree
Showing 323 changed files with 2,070 additions and 1,613 deletions.
23 changes: 20 additions & 3 deletions packages/osd-charts/.eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ module.exports = {
'plugin:prettier/recommended',
'plugin:react/recommended',
],
plugins: ['@typescript-eslint', 'import', 'jest', 'unicorn', 'file-header'],
plugins: ['@typescript-eslint', 'import', 'jest', 'unicorn', 'file-header', 'react-hooks'],

env: {
es6: true,
Expand Down Expand Up @@ -104,6 +104,8 @@ module.exports = {
'block',
['-\\*-(.*)-\\*-', 'eslint(.*)', '@jest-environment'],
],
'react-hooks/rules-of-hooks': 'error',
'react-hooks/exhaustive-deps': 'warn',
},
settings: {
'import/resolver': {
Expand All @@ -127,11 +129,26 @@ module.exports = {
files: ['stories/**/*.tsx', 'stories/**/*.ts', '*.test.ts', '*.test.tsx'],
rules: {
'no-restricted-properties': [
2,
process.env.NODE_ENV === 'production' ? 2 : 1,
{
object: 'Math',
property: 'random',
message: 'Please use the `getRandomNumber` to create seeded random function in `stories/` and `tests/`',
message: 'Please use the `getRandomNumber` to create seeded random function in `stories/` and `tests/`.',
},
{
object: 'describe',
property: 'only',
message: 'Please remove before committing changes.',
},
{
object: 'it',
property: 'only',
message: 'Please remove before committing changes.',
},
{
object: 'test',
property: 'only',
message: 'Please remove before committing changes.',
},
],
},
Expand Down
37 changes: 33 additions & 4 deletions packages/osd-charts/.playground/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -9,20 +9,49 @@
html,
body {
background: blanchedalmond !important;
/*margin-left: 8px !important;*/
/*padding: 8px !important;*/
/*height: 100%;*/
/*width: 2000px;
}
#root {
position: absolute;
/*
top: 0;
left: 0;
*/
/* width: 100%;
height: 100%;*/
/* overflow-x: hidden; */
}
.chart {
background: white;
width: 800px;
height: 300px;
margin: 20px;
/*display: inline-block;
position: relative;
*/
width: 100%;
height: 500px;
overflow: auto;
}

.testing {
background: aquamarine;
position: relative;
width: 100%;
overflow: auto;
}
.page {
padding: 100px;
}
label {
display: block;
}
</style>
</head>
<body>
<div id="root"></div>
<div class="page">
<div id="root"></div>
</div>
<script src="bundle.js" type="text/javascript"></script>
</body>
</html>
36 changes: 2 additions & 34 deletions packages/osd-charts/.playground/playground.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,45 +17,13 @@
* under the License. */

import React from 'react';
import { Chart, Axis, Position, Settings, AreaSeries, ScaleType, DataGenerator } from '../src';
import { getRandomNumberGenerator } from '../src/mocks/utils';
import { Example } from '../stories/treemap/6_custom_style';

const dg = new DataGenerator(500, getRandomNumberGenerator());
const basicData = dg.generateBasicSeries();
export class Playground extends React.Component {
state = {
data: basicData,
};
onBrushEnd = () => {
this.setState({ data: [] });
setTimeout(() => {
this.setState({
data: dg.generateBasicSeries(),
});
}, 100);
};
render() {
return (
<div className="testing">
<div className="chart">
<Chart className="story-chart">
<Settings onBrushEnd={this.onBrushEnd} />
<Axis id="bottom" position={Position.Bottom} title="bottom" showOverlappingTicks={true} />
<Axis id="left" title="left" position={Position.Left} tickFormat={(d) => Number(d).toFixed(2)} />
<Axis id="top" position={Position.Top} title="top" showOverlappingTicks={true} />
<Axis id="right" title="right" position={Position.Right} tickFormat={(d) => Number(d).toFixed(2)} />
{this.state.data.length > 0 && (
<AreaSeries
id="lines"
xScaleType={ScaleType.Linear}
yScaleType={ScaleType.Linear}
xAccessor="x"
yAccessors={['y']}
data={this.state.data}
/>
)}
</Chart>
</div>
<div className="chart">{Example()}</div>
</div>
);
}
Expand Down
77 changes: 50 additions & 27 deletions packages/osd-charts/api/charts.api.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
```ts

import { $Values } from 'utility-types';
import { ComponentType } from 'react';
import React from 'react';

// @public
Expand Down Expand Up @@ -403,6 +404,9 @@ export const CurveType: Readonly<{
// @public (undocumented)
export type CurveType = $Values<typeof CurveType>;

// @public
export type CustomTooltip = ComponentType<TooltipInfo>;

// Warning: (ae-missing-release-tag) "DARK_THEME" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
//
// @public (undocumented)
Expand Down Expand Up @@ -493,14 +497,10 @@ export const DEFAULT_MISSING_COLOR = "red";
// @public (undocumented)
export const DEFAULT_SETTINGS_SPEC: SettingsSpec;

// Warning: (ae-missing-release-tag) "DEFAULT_TOOLTIP_SNAP" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
//
// @public (undocumented)
// @public
export const DEFAULT_TOOLTIP_SNAP = true;

// Warning: (ae-missing-release-tag) "DEFAULT_TOOLTIP_TYPE" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
//
// @public (undocumented)
// @public
export const DEFAULT_TOOLTIP_TYPE: "vertical";

// Warning: (ae-missing-release-tag) "DefaultSettingsProps" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
Expand Down Expand Up @@ -678,9 +678,9 @@ export type HistogramModeAlignment = 'start' | 'center' | 'end';
//
// @public (undocumented)
export const HistogramModeAlignments: Readonly<{
Start: HistogramModeAlignment;
Center: HistogramModeAlignment;
End: HistogramModeAlignment;
Start: LineAlignSetting;
Center: LineAlignSetting;
End: LineAlignSetting;
}>;

// Warning: (ae-forgotten-export) The symbol "BinaryAccessorFn" needs to be exported by the entry point index.d.ts
Expand Down Expand Up @@ -931,6 +931,28 @@ export const PartitionLayout: Readonly<{
// @public (undocumented)
export type PartitionLayout = $Values<typeof PartitionLayout>;

// @public
export const Placement: Readonly<{
Top: "top";
Bottom: "bottom";
Left: "left";
Right: "right";
TopStart: "top-start";
TopEnd: "top-end";
BottomStart: "bottom-start";
BottomEnd: "bottom-end";
RightStart: "right-start";
RightEnd: "right-end";
LeftStart: "left-start";
LeftEnd: "left-end";
Auto: "auto";
AutoStart: "auto-start";
AutoEnd: "auto-end";
}>;

// @public
export type Placement = $Values<typeof Placement>;

// Warning: (ae-missing-release-tag) "PointerEvent" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
//
// @public (undocumented)
Expand Down Expand Up @@ -1296,7 +1318,7 @@ export interface SettingsSpec extends Spec {
showLegend: boolean;
showLegendExtra: boolean;
theme?: PartialTheme | PartialTheme[];
tooltip: TooltipType | TooltipProps;
tooltip: TooltipSettings;
// Warning: (ae-forgotten-export) The symbol "Domain" needs to be exported by the entry point index.d.ts
//
// (undocumented)
Expand Down Expand Up @@ -1428,23 +1450,28 @@ export type TickStyle = StrokeStyle & Visible;
// @public (undocumented)
export function timeFormatter(format: string): TickFormatter;

// Warning: (ae-missing-release-tag) "TooltipProps" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
//
// @public (undocumented)
// @public
export interface TooltipInfo {
header: TooltipValue | null;
values: TooltipValue[];
}

// @public
export interface TooltipProps {
// (undocumented)
boundary?: HTMLElement | 'chart';
customTooltip?: CustomTooltip;
fallbackPlacements?: Placement[];
headerFormatter?: TooltipValueFormatter;
// (undocumented)
placement?: Placement;
snap?: boolean;
// (undocumented)
type?: TooltipType;
// (undocumented)
// @alpha
unit?: string;
}

// Warning: (ae-missing-release-tag) "TooltipType" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
// Warning: (ae-missing-release-tag) "TooltipType" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
//
// @public
export type TooltipSettings = TooltipType | TooltipProps;

// @public
export const TooltipType: Readonly<{
VerticalCursor: "vertical";
Expand All @@ -1453,12 +1480,10 @@ export const TooltipType: Readonly<{
None: "none";
}>;

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

// Warning: (ae-missing-release-tag) "TooltipValue" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
//
// @public (undocumented)
// @public
export interface TooltipValue {
color: Color;
isHighlighted: boolean;
Expand All @@ -1470,9 +1495,7 @@ export interface TooltipValue {
valueAccessor?: Accessor;
}

// Warning: (ae-missing-release-tag) "TooltipValueFormatter" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal)
//
// @public (undocumented)
// @public
export type TooltipValueFormatter = (data: TooltipValue) => JSX.Element | string;

// @public
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.
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.
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.
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.
2 changes: 2 additions & 0 deletions packages/osd-charts/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,7 @@
"eslint-plugin-jest": "^23.0.4",
"eslint-plugin-prettier": "^3.1.2",
"eslint-plugin-react": "^7.19.0",
"eslint-plugin-react-hooks": "^4.0.3",
"eslint-plugin-unicorn": "^17.2.0",
"geckodriver": "^1.19.1",
"husky": "^3.1.0",
Expand Down Expand Up @@ -168,6 +169,7 @@
"webpack-dev-server": "^3.3.1"
},
"dependencies": {
"@popperjs/core": "^2.4.0",
"classnames": "^2.2.6",
"d3-array": "^1.2.4",
"d3-collection": "^1.0.7",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ import { computeLegendSelector } from './selectors/compute_legend';
import { getLegendItemsLabels } from './selectors/get_legend_items_labels';
import { HighlighterFromHover } from '../renderer/dom/highlighter_hover';
import { HighlighterFromLegend } from '../renderer/dom/highlighter_legend';
import { getPieSpecOrNull } from './selectors/pie_spec';
import { getPieSpec } from './selectors/pie_spec';

const EMPTY_MAP = new Map();

Expand All @@ -47,7 +47,7 @@ export class PartitionState implements InternalChartState {
}
chartType = ChartTypes.Partition;
isInitialized(globalState: GlobalChartState) {
return globalState.specsInitialized && getPieSpecOrNull(globalState) !== null;
return globalState.specsInitialized && getPieSpec(globalState) !== null;
}
isBrushAvailable() {
return false;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
import createCachedSelector from 're-reselect';
import { LegendItem } from '../../../../commons/legend';
import { getChartIdSelector } from '../../../../state/selectors/get_chart_id';
import { getPieSpecOrNull } from './pie_spec';
import { getPieSpec } from './pie_spec';
import { partitionGeometries } from './geometries';
import { getSettingsSpecSelector } from '../../../../state/selectors/get_settings_specs';
import { PrimitiveValue } from '../../layout/utils/group_by_rollup';
Expand All @@ -29,7 +29,7 @@ import { Position } from '../../../../utils/commons';

/** @internal */
export const computeLegendSelector = createCachedSelector(
[getPieSpecOrNull, getSettingsSpecSelector, partitionGeometries, getFlatHierarchy],
[getPieSpec, getSettingsSpecSelector, partitionGeometries, getFlatHierarchy],
(pieSpec, settings, geoms, sortedItems): LegendItem[] => {
if (!pieSpec) {
return [];
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
import createCachedSelector from 're-reselect';
import { getTree } from './tree';
import { getChartIdSelector } from '../../../../state/selectors/get_chart_id';
import { getPieSpecOrNull } from './pie_spec';
import { getPieSpec } from './pie_spec';
import { HierarchyOfArrays, CHILDREN_KEY } from '../../layout/utils/group_by_rollup';
import { Layer } from '../../specs';
import { LegendItemLabel } from '../../../../state/selectors/get_legend_items_labels';
Expand All @@ -28,7 +28,7 @@ import { SettingsSpec } from '../../../../specs';

/** @internal */
export const getLegendItemsLabels = createCachedSelector(
[getPieSpecOrNull, getSettingsSpecSelector, getTree],
[getPieSpec, getSettingsSpecSelector, getTree],
(pieSpec, { legendMaxDepth }, tree): LegendItemLabel[] => {
if (!pieSpec) {
return [];
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ import { GlobalChartState, PointerState } from '../../../../state/chart_state';
import { getSettingsSpecSelector } from '../../../../state/selectors/get_settings_specs';
import { SettingsSpec, LayerValue } from '../../../../specs';
import { getPickedShapesLayerValues } from './picked_shapes';
import { getPieSpecOrNull } from './pie_spec';
import { getPieSpec } from './pie_spec';
import { ChartTypes } from '../../..';
import { SeriesIdentifier } from '../../../../commons/series_id';
import { isClicking } from '../../../../state/utils';
Expand All @@ -41,7 +41,7 @@ export function createOnElementClickCaller(): (state: GlobalChartState) => void
return (state: GlobalChartState) => {
if (selector === null && state.chartType === ChartTypes.Partition) {
selector = createCachedSelector(
[getPieSpecOrNull, getLastClickSelector, getSettingsSpecSelector, getPickedShapesLayerValues],
[getPieSpec, getLastClickSelector, getSettingsSpecSelector, getPickedShapesLayerValues],
(pieSpec, lastClick: PointerState | null, settings: SettingsSpec, pickedShapes): void => {
if (!pieSpec) {
return;
Expand Down
Loading

0 comments on commit 61d1d9a

Please sign in to comment.