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

Commit

Permalink
feat(stacked-series-chart): Adding heat fields
Browse files Browse the repository at this point in the history
  - Heat Fields overlap supported
  - Light overlay rendering (removing unnecessary code)
  - HeatField example and e2e
  - Overlay fix to avoid tooltip to close when unpinned
  - Fix bug for event-chart ticks
  • Loading branch information
kennyamr authored and tomheller committed Nov 17, 2021
1 parent 5b2e75f commit a36cf83
Show file tree
Hide file tree
Showing 27 changed files with 847 additions and 133 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -34,11 +34,16 @@ import {
continuousAxisTypeDate,
continuousAxisTypeLinear,
fullTrackBtn,
getHeatFieldArea,
getHeatFieldTooltip,
getHeatFieldItemByLevel,
getHeatFieldLevel,
getLabel,
getLegendItem,
getSlice,
getTick,
getTrack,
heatFieldTypeNormal,
labels,
legend,
legendItems,
Expand All @@ -63,6 +68,7 @@ import {
tracks,
unselectBtn,
valueAxis,
heatFieldTypeOverlap,
} from './stacked-series-chart.po';

// Reduced speed of hovering should get our e2e tests stable.
Expand All @@ -78,6 +84,8 @@ const selectableTrackClassname = 'dt-stacked-series-chart-track-selectable';
const selectableSliceClassname = 'dt-stacked-series-chart-slice-selectable';

const selectedSliceClassname = 'dt-stacked-series-chart-slice-selected';
const selectedHeatFieldClassname =
'dt-stacked-series-chart-heat-field-selected';

const compactModeClassname = 'dt-stacked-series-chart-series-axis-compact-mode';

Expand Down Expand Up @@ -454,3 +462,105 @@ test('should render date chart with format and auto-fitting ticks', async (testC
.expect(getLabel(1).textContent)
.match(/13:00/);
});

test('should render Heat Fields, even with overlaps, and show tooltip', async (testController: TestController) => {
const checkHeatFieldWrapper = async (
selectedHeatField: Selector,
isColumn: boolean,
heatFieldsByLevel: number[],
heatFieldTooltipText: RegExp,
) => {
const getLineWidth = () =>
isColumn ? selectedHeatField.clientHeight : selectedHeatField.clientWidth;
const getAreaSize = (selector) =>
isColumn ? selector.clientWidth : selector.clientHeight;

await testController
.expect(getHeatFieldLevel(0).count)
.eql(heatFieldsByLevel[0])
.expect(getHeatFieldLevel(1).count)
.eql(heatFieldsByLevel[1])
.expect(getHeatFieldLevel(2).count)
.eql(heatFieldsByLevel[2])
.expect(getLineWidth())
.eql(8)
.expect(selectedHeatField.classNames)
.notContains(selectedHeatFieldClassname)

// Select first heat field and check tooltip
.click(selectedHeatField)
.expect(selectedHeatField.classNames)
.contains(selectedHeatFieldClassname)
.expect(getLineWidth())
.eql(12)

// Check expected text in tooltip
.expect(getHeatFieldTooltip.textContent)
.match(heatFieldTooltipText);

await testController
.expect(getAreaSize(selectedHeatField))
.eql(await getAreaSize(getHeatFieldArea));

await testController
.click(selectedHeatField)
.expect(getLineWidth())
.eql(8)
.expect(getHeatFieldTooltip.count)
.eql(0);
};

await testController
// maximize window so that overlay is not closed due to scroll
.maximizeWindow()
// Select heat fields
.click(resetBtn)
.click(heatFieldTypeNormal);

await checkHeatFieldWrapper(
getHeatFieldItemByLevel(0, 0),
false,
[2, 0, 0],
/HeatField 1/,
);

// Try overlap
await testController.click(heatFieldTypeOverlap);

await checkHeatFieldWrapper(
getHeatFieldItemByLevel(1, 1),
false,
[1, 3, 1],
/HeatField 4/,
);

// Check that everything works in column mode as well
await testController.click(columnBtn);

await checkHeatFieldWrapper(
getHeatFieldItemByLevel(1, 1),
true,
[1, 3, 1],
/HeatField 4/,
);

// Try the same for date data
await testController.click(continuousAxisTypeDate).click(heatFieldTypeNormal);

await checkHeatFieldWrapper(
getHeatFieldItemByLevel(0, 0),
true,
[2, 0, 0],
/HeatField 1/,
);

// Try overlap for date data
await testController.click(heatFieldTypeOverlap);

await checkHeatFieldWrapper(
getHeatFieldItemByLevel(1, 0),
true,
[1, 1, 0],
/HeatField 2/,
);
});
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
(selectedChange)="selected = $event"
[mode]="mode"
[series]="usedSeries"
[heatFields]="heatFieldsByType[continuousAxisType][heatFieldType]"
[valueDisplayMode]="valueDisplayMode"
[fillMode]="fillMode"
[visibleValueAxis]="visibleValueAxis"
Expand All @@ -27,6 +28,11 @@
<strong>{{ tooltip.seriesOrigin.label }}</strong>
<div>{{ tooltip.origin.label }}: {{ tooltip.origin.value }}</div>
</ng-template>

<ng-template dtStackedSeriesChartHeatFieldOverlay let-heatField>
<h6>HeatField data</h6>
<div>{{ heatField.name }}</div>
</ng-template>
</dt-stacked-series-chart>

<div>
Expand Down Expand Up @@ -266,3 +272,15 @@
10:45:00:000AM
</button>
</div>

<div>
<button (click)="heatFieldType = 'none'" id="chart-heat-field-none">
None
</button>
<button (click)="heatFieldType = 'normal'" id="chart-heat-field-normal">
Normal
</button>
<button (click)="heatFieldType = 'overlap'" id="chart-heat-field-overlap">
Overlap
</button>
</div>
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,10 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { DtStackedSeriesChartSeries } from '@dynatrace/barista-components/stacked-series-chart';
import {
DtStackedSeriesChartSeries,
DtStackedSeriesHeatField,
} from '@dynatrace/barista-components/stacked-series-chart';
import { DtColors } from '@dynatrace/barista-components/theming';

export const stackedSeriesChartCoffeeMock: DtStackedSeriesChartSeries[] = [
Expand Down Expand Up @@ -85,7 +88,61 @@ export const stackedSeriesChartCoffeeMock: DtStackedSeriesChartSeries[] = [
},
];

export const stackedSeriesChartDemoDataConvertedBouncedDates = [
export const stackedSeriesCoffeeHeatFieldMock: DtStackedSeriesHeatField[] = [
{
start: 'Espresso',
end: 'Macchiato',
data: {
name: 'HeatField 1',
},
},
{
start: 'Macchiato',
data: {
name: 'HeatField 2',
},
},
];

export const stackedSeriesCoffeeHeatFieldOverlapMock: DtStackedSeriesHeatField[] =
[
{
start: 'Espresso',
end: 'Macchiato',
data: {
name: 'HeatField 1',
},
},
{
start: 'Espresso',
data: {
name: 'HeatField 2',
},
},
{
start: 'Americano',
end: 'Mocha',
data: {
name: 'HeatField 3',
},
},
{
start: 'Macchiato',
end: 'Americano',
data: {
name: 'HeatField 4',
},
},
{
start: 'Americano',
end: 'Americano',
data: {
name: 'HeatField 5',
},
},
];

export const stackedSeriesChartConvertedBouncedDatesMock = [
{
label: '11:35',
nodes: [
Expand Down Expand Up @@ -647,3 +704,37 @@ export const stackedSeriesChartDemoDataConvertedBouncedDates = [
],
},
];

export const stackedSeriesChartConvertedBouncedDateHeatFieldMock = [
{
start: '11:35',
end: '12:00',
data: {
name: 'HeatField 1',
},
},
{
start: '12:35',
end: '13:50',
data: {
name: 'HeatField 2',
},
},
];

export const stackedSeriesChartConvertedBouncedDateHeatFieldOverlapMock = [
{
start: '12:00',
end: '12:55',
data: {
name: 'HeatField 1',
},
},
{
start: '12:35',
end: '13:50',
data: {
name: 'HeatField 2',
},
},
];
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ export const overlay = Selector('.dt-overlay-container');
export const columnChart = Selector('.dt-stacked-series-chart-column');
export const barChart = Selector('.dt-stacked-series-chart-bar');

export const trackWrapper = Selector('.dt-stacked-series-chart-track-wrapper');
export const tracks = Selector('.dt-stacked-series-chart-track');
export const slices = Selector('.dt-stacked-series-chart-slice');
export const labels = Selector(
Expand All @@ -32,6 +33,13 @@ export const valueAxis = Selector('.dt-stacked-series-chart-value-axis');
export const ticks = Selector('.dt-stacked-series-chart-axis-tick');
export const legend = Selector('.dt-stacked-series-chart-legend');
export const legendItems = Selector('dt-legend-item');
export const heatFieldWrapper = Selector(
'.dt-stacked-series-chart-heat-field-wrapper',
);
export const getHeatFieldArea = trackWrapper.child(
'.dt-stacked-series-chart-heat-field-area',
);
export const getHeatFieldTooltip = Selector('dt-overlay-container div');

export const getTrack = (track: number) => tracks.nth(track);
export const getSlice = (track: number, slice: number) =>
Expand All @@ -41,6 +49,10 @@ export const getLegendItem = (item: number) =>
Selector(`dt-legend-item`).nth(item);
export const getTick = (tick: number) =>
Selector(`.dt-stacked-series-chart-axis-tick`).nth(tick);
export const getHeatFieldLevel = (level: number) =>
heatFieldWrapper.child(`.dt-stacked-series-chart-heat-field-level-${level}`);
export const getHeatFieldItemByLevel = (level: number, item: number) =>
getHeatFieldLevel(level).nth(item);

// controls
export const resetBtn = Selector('#chart-reset');
Expand Down Expand Up @@ -133,3 +145,7 @@ export const continuousAxisFormat2f = Selector(
export const continuousAxisFormat7f = Selector(
'#chart-continuous-axis-format-7f',
);

export const heatFieldTypeNone = Selector('#chart-heat-field-none');
export const heatFieldTypeNormal = Selector('#chart-heat-field-normal');
export const heatFieldTypeOverlap = Selector('#chart-heat-field-overlap');
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,11 @@ import {
} from '@dynatrace/barista-components/stacked-series-chart';
import {
stackedSeriesChartCoffeeMock,
stackedSeriesChartDemoDataConvertedBouncedDates,
stackedSeriesChartConvertedBouncedDateHeatFieldMock,
stackedSeriesChartConvertedBouncedDateHeatFieldOverlapMock,
stackedSeriesChartConvertedBouncedDatesMock,
stackedSeriesCoffeeHeatFieldMock,
stackedSeriesCoffeeHeatFieldOverlapMock,
} from './stacked-series-chart.mocks';
import { timeHour, timeMinute } from 'd3-time';

Expand Down Expand Up @@ -67,13 +71,33 @@ export class DtE2EStackedSeriesChart {
linear: ['$.2f', '$.7f'],
date: ['%H:%M', '%H:%M:%S:%L%p'],
};

continuousAxisMapByType = {
linear: (_, index) => index * 0.5,
linear: ({ origin }) =>
this.usedSeries.reduce(
(obj, { label }, index) => ({ ...obj, [label]: index * 0.5 }),
{},
)[origin.label],
date: ({ origin }) => {
const [hours, minutes] = origin.label.split(':').map(Number);
return new Date(0, 0, 0, hours, minutes, 0, 0);
},
};
heatFieldsByType = {
none: {
normal: stackedSeriesCoffeeHeatFieldMock,
overlap: stackedSeriesCoffeeHeatFieldOverlapMock,
},
linear: {
normal: stackedSeriesCoffeeHeatFieldMock,
overlap: stackedSeriesCoffeeHeatFieldOverlapMock,
},
date: {
normal: stackedSeriesChartConvertedBouncedDateHeatFieldMock,
overlap: stackedSeriesChartConvertedBouncedDateHeatFieldOverlapMock,
},
};
heatFieldType = 'none';

series: DtStackedSeriesChartSeries[] = stackedSeriesChartCoffeeMock;
usedSeries: DtStackedSeriesChartSeries[] = this.series;
Expand Down Expand Up @@ -111,6 +135,7 @@ export class DtE2EStackedSeriesChart {
this.changeContinuousAxisType('none');
this.continuousAxisInterval = null;
this.continuousAxisFormat = undefined;
this.heatFieldType = 'none';
}

setElementWidth(width: string): void {
Expand All @@ -125,10 +150,11 @@ export class DtE2EStackedSeriesChart {

this.continuousAxisMap = this.continuousAxisMapByType[type];
if (type === 'date') {
this.series = stackedSeriesChartDemoDataConvertedBouncedDates;
this.series = stackedSeriesChartConvertedBouncedDatesMock;
} else {
this.series = stackedSeriesChartCoffeeMock;
}

const continuousAxisFormats = this.continuousAxisFormatsByType[type] || [];
if (!continuousAxisFormats.includes(this.continuousAxisFormat)) {
this.continuousAxisFormat = continuousAxisFormats[0];
Expand Down
Loading

0 comments on commit a36cf83

Please sign in to comment.