Skip to content
This repository has been archived by the owner on Sep 11, 2024. It is now read-only.

Commit

Permalink
feat(chart): Adds a DtChartTooltipConfig to customize the positioning…
Browse files Browse the repository at this point in the history
… of the tooltip inside the chart.
  • Loading branch information
lukett89 authored and tomheller committed Nov 25, 2020
1 parent c9553ec commit 8c676d2
Show file tree
Hide file tree
Showing 6 changed files with 256 additions and 114 deletions.
55 changes: 37 additions & 18 deletions libs/barista-components/chart/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,19 +28,19 @@ component about viewport changes that trigger a reflow of the `dt-chart`.

## Inputs

| Name | Type | Default | Description |
| -------------- | ----------------------------------------------------------------------------------------------------- | ----------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `options` | `Observable<DtChartOptions> | DtChartOptions | undefined` | `undefined` | Sets options for the chart. `DtChartOptions` extends from `Highcharts.Options`, but removes the series property. The series property is passed as separate input. |
| `series` | `Observable<Highcharts.IndividualSeriesOptions[]> | Highcharts.IndividualSeriesOptions[] | undefined` | `undefined` | Sets the series of the chart. The type can either be an observable or a static array. |
| `loading-text` | `string` | | The loading text of the loading distractor. |
| Name | Type | Default | Description |
| -------------- | ------------------------------------------------------------------------------------------------------------- | ----------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `options` | Observable<DtChartOptions> &#124; DtChartOptions &#124; undefined> | `undefined` | Sets options for the chart. `DtChartOptions` extends from `Highcharts.Options`, but removes the series property. The series property is passed as separate input. |
| `series` | Observable<Highcharts.IndividualSeriesOptions[]> &#124; Highcharts.IndividualSeriesOptions[] &#124; undefined | `undefined` | Sets the series of the chart. The type can either be an observable or a static array. |
| `loading-text` | `string` | | The loading text of the loading distractor. |

## Outputs

| Name | Type | Description |
| ------------------------ | -------------------------------------------------- | -------------------------------------------------------------------------------- |
| `updated` | `EventEmitter<void>` | Event emitted when the chart options or series are updated. |
| `tooltipOpenChange` | `EventEmitter<boolean>` | Event emitted when the chart tooltip opens or closes. |
| `tooltipDataChange` | `EventEmitter<DtChartTooltipEvent | null>` | Event emitted when the tooltip data changes. |
| `tooltipDataChange` | EventEmitter<DtChartTooltipEvent &#124; null> | Event emitted when the tooltip data changes. |
| `seriesVisibilityChange` | `EventEmitter<DtChartSeriesVisibilityChangeEvent>` | Event emitted when a series visibility changes because a legend item was clicked |

## Types
Expand Down Expand Up @@ -118,13 +118,32 @@ declare the variable for the implicit context on the `ng-template`.
```html
<dt-chart ...>
<dt-chart-tooltip>
<ng-template let-tooltipdata>
{{tooltipdata.point.y}}
</ng-template>
<ng-template let-tooltipdata> {{ tooltipdata.point.y }} </ng-template>
</dt-chart-tooltip>
</dt-chart>
```

It is possible to provide a custom position function for the `dt-chart-tooltip`
by providing a `DtChartTooltipConfig` through providers, as it is done in the
following example:

```javascript
@Component({
selector: 'dt-example-chart-bar',
templateUrl: 'chart-bar-example.html',
providers: [
{
provide: DT_CHART_TOOLTIP_CONFIG,
useValue: {
positionFunction: myCustomPositionFunction,
},
},
],
})
```

<ba-live-example name="DtExampleChartBar" fullwidth></ba-live-example>

## Selection area

Within a chart you can add a `dt-chart-range` to select a timeframe or a
Expand Down Expand Up @@ -183,7 +202,7 @@ accessibility standards.
| Name | Type | Default | Description |
| ----------------------- | ------------------ | -------- | ------------------------------------------------------------------------------------------------------------------------- |
| `min` | `number` | `300000` | The minimum range that can be created in milliseconds, by default the minimum range is 5 minutes. |
| `max` | `number | null` | `null` | The maximum range that can be created in a time format. If not set, the range will be capped at the borders of the chart. |
| `max` | number &#124; null | `null` | The maximum range that can be created in a time format. If not set, the range will be capped at the borders of the chart. |
| `value` | `[number, number]` | `[0,0]` | The time frame on the chart's x-axis where the range should be placed. |
| `ariaLabelSelectedArea` | `string` | `''` | Aria label of the selected area that is created. |
| `ariaLabelLeftHandle` | `string` | `''` | Aria label of the left handle of the selected area that can resize the selected frame. |
Expand Down Expand Up @@ -274,14 +293,14 @@ an overload. To indicate this use case, add a heatfield with `color` set to

### Inputs

| Name | Type | Default | Description |
| ----------------- | ------------------ | ----------- | --------------------------------------------------------------------------- |
| `start` | `number` | | The start numerical/date value on the x-axis of the chart. |
| `end` | `number` | | The end numerical/date value on the x-axis of the chart. |
| `active` | `boolean` | `false` | Whether the heatfield is active. |
| `aria-label` | `string` | `undefined` | The aria label used for the heatfield button. |
| `aria-labelledby` | `string` | `undefined` | ARIA reference to a label describing the icon in the consumption component. |
| `color` | `'error' | 'main'` | `'error'` | Sets the color of the heatfield. |
| Name | Type | Default | Description |
| ----------------- | --------------------- | ----------- | --------------------------------------------------------------------------- |
| `start` | `number` | | The start numerical/date value on the x-axis of the chart. |
| `end` | `number` | | The end numerical/date value on the x-axis of the chart. |
| `active` | `boolean` | `false` | Whether the heatfield is active. |
| `aria-label` | `string` | `undefined` | The aria label used for the heatfield button. |
| `aria-labelledby` | `string` | `undefined` | ARIA reference to a label describing the icon in the consumption component. |
| `color` | 'error' &#124; 'main' | `'error'` | Sets the color of the heatfield. |

To make our components accessible it is obligatory to provide either an
`aria-label` or `aria-labelledby`.
Expand Down
5 changes: 5 additions & 0 deletions libs/barista-components/chart/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,11 @@ export * from './src/chart.interface';
export * from './src/chart-config';
export * from './src/heatfield/index';
export * from './src/tooltip/chart-tooltip';
export {
DtChartTooltipConfig,
DtChartTooltipPositionFn,
DT_CHART_TOOLTIP_CONFIG,
} from './src/tooltip/chart-tooltip-position';
export { DtChartTooltipData } from './src/highcharts/highcharts-tooltip-types';

export { DtChartRange } from './src/range/range';
Expand Down
111 changes: 111 additions & 0 deletions libs/barista-components/chart/src/tooltip/chart-tooltip-position.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
/**
* @license
* Copyright 2020 Dynatrace LLC
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

import { DtChart, DtChartTooltipData } from '../..';
import { PlotBackgroundInfo } from '../utils';
import { ConnectedPosition } from '@angular/cdk/overlay';
import { InjectionToken } from '@angular/core';
import { isDefined } from '@dynatrace/barista-components/core';

/** InjectionToken of the Tooltip options. */
export const DT_CHART_TOOLTIP_CONFIG = new InjectionToken<string>(
'DT_CHART_TOOLTIP_CONFIG',
);

/** The config that can be passed to the dt-chart-tooltip component for customization */
export interface DtChartTooltipConfig {
positionFunction?: DtChartTooltipPositionFn;
}

export type DtChartTooltipPositionFn = (
data: DtChartTooltipData,
chart: DtChart,
plotBackgroundInfo?: PlotBackgroundInfo,
) => { x: number; y: number };

/**
* Calculate an origin point that can be used to position the tooltip.
*/
export const getDefaultTooltipPosition = (
data: DtChartTooltipData,
chart: DtChart,
plotBackgroundInfo: PlotBackgroundInfo,
): { x: number; y: number } => {
const containerElement: HTMLElement = chart._container.nativeElement;
const containerElementBB = containerElement.getBoundingClientRect();
const { x, y } = getHighchartsTooltipPosition(data, plotBackgroundInfo);
return {
x: containerElementBB.left + x,
y: containerElementBB.top + y,
};
};

/**
* highcharts provides the tooltip position differently depending on the series type
* Pie chart: data.point.point.tooltipPos[x, y]
* Category: data.points[0].point.tooltipPos[x, whatever, whatever]
* Mixed multiple series(line, column): data.points[0].point.tooltipPos[x, whatever, whatever]
* Area as first: data.points[0].point.x => xAxis.toPixel(x)
*/
const getHighchartsTooltipPosition = (
data: DtChartTooltipData,
plotBackgroundInfo: PlotBackgroundInfo,
): { x: number; y: number } => {
const isPieChart = !isDefined(data.points);
const hasAreaFirstSeries =
data.points &&
data.points[0].point &&
!(data.points[0].point as any).tooltipPos;
let x: number;
// set y position for all charts in the middle of the plotbackground vertically
// tslint:disable-next-line:no-magic-numbers
let y = plotBackgroundInfo.height / 2 + plotBackgroundInfo.top;
if (isPieChart) {
const tooltipPos = (data.point!.point as any).tooltipPos;
x = tooltipPos![0];
// override the y position for pie charts
y = tooltipPos![1];
} else if (hasAreaFirstSeries) {
const point = data.points![0].point;
const xAxis = data.points![0].series!.xAxis;
x = xAxis.toPixels(point.x as number, false);
} else {
x = (data.points![0].point as any).tooltipPos![0] + plotBackgroundInfo.left;
}

return { x, y };
};

/** Default horizontal offset for the tooltip */
export const DT_CHART_TOOLTIP_DEFAULT_OFFSET = 10;

/** Positions for the chart tooltip */
export const DT_CHART_DEFAULT_TOOLTIP_POSITIONS: ConnectedPosition[] = [
{
originX: 'start',
originY: 'center',
overlayX: 'end',
overlayY: 'center',
offsetX: -DT_CHART_TOOLTIP_DEFAULT_OFFSET,
},
{
originX: 'end',
originY: 'center',
overlayX: 'start',
overlayY: 'center',
offsetX: DT_CHART_TOOLTIP_DEFAULT_OFFSET,
},
];
Loading

0 comments on commit 8c676d2

Please sign in to comment.