From 57bc63318b3e916e8a15b062c402d11faa480e6c Mon Sep 17 00:00:00 2001 From: Aaron Steinfeld Date: Mon, 2 Aug 2021 18:01:35 -0400 Subject: [PATCH 1/3] feat: allow custom tooltip titles --- .../cartesian/cartesian-chart.component.ts | 16 +++++++++++----- .../src/shared/components/cartesian/chart.ts | 1 + .../data/graphql/explore/explore-result.ts | 2 +- 3 files changed, 13 insertions(+), 6 deletions(-) diff --git a/projects/observability/src/shared/components/cartesian/cartesian-chart.component.ts b/projects/observability/src/shared/components/cartesian/cartesian-chart.component.ts index 51f2ee888..d825c2329 100644 --- a/projects/observability/src/shared/components/cartesian/cartesian-chart.component.ts +++ b/projects/observability/src/shared/components/cartesian/cartesian-chart.component.ts @@ -165,12 +165,8 @@ export class CartesianChartComponent implements OnChanges, OnDestroy { return undefined; } - const firstXValue = defaultXDataAccessor(data[0].dataPoint); - const xAsDate = this.dateCoercer.coerce(firstXValue); - const title = xAsDate ? this.dateFormatter.format(xAsDate) : String(firstXValue); - return { - title: title, + title: this.resolveTooltipTitle(data[0]), labeledValues: data.map(singleValue => ({ label: singleValue.context.name, value: defaultYDataAccessor(singleValue.dataPoint), @@ -179,4 +175,14 @@ export class CartesianChartComponent implements OnChanges, OnDestroy { })) }; } + + private resolveTooltipTitle(location: MouseLocationData>): string { + const series = location.context; + if (series.getTooltipTitle) { + return series.getTooltipTitle(location.dataPoint); + } + const xValue = defaultXDataAccessor(location.dataPoint); + const xAsDate = this.dateCoercer.coerce(xValue); + return xAsDate ? this.dateFormatter.format(xAsDate) : String(xValue); + } } diff --git a/projects/observability/src/shared/components/cartesian/chart.ts b/projects/observability/src/shared/components/cartesian/chart.ts index c666e4cbf..545ada8f5 100644 --- a/projects/observability/src/shared/components/cartesian/chart.ts +++ b/projects/observability/src/shared/components/cartesian/chart.ts @@ -30,6 +30,7 @@ export interface Series { type: CartesianSeriesVisualizationType; stacking?: boolean; hide?: boolean; + getTooltipTitle?(datum: TInterval): string; } export interface Band { diff --git a/projects/observability/src/shared/dashboard/data/graphql/explore/explore-result.ts b/projects/observability/src/shared/dashboard/data/graphql/explore/explore-result.ts index afb063b51..52cdedfb2 100644 --- a/projects/observability/src/shared/dashboard/data/graphql/explore/explore-result.ts +++ b/projects/observability/src/shared/dashboard/data/graphql/explore/explore-result.ts @@ -90,7 +90,7 @@ export class ExploreResult { const startTime = Math.floor(this.timeRange.from.valueOf() / intervalDuration) * intervalDuration; const endTime = Math.ceil(this.timeRange.to.valueOf() / intervalDuration) * intervalDuration; - for (let timestamp = startTime; timestamp <= endTime; timestamp = timestamp + intervalDuration) { + for (let timestamp = startTime; timestamp < endTime; timestamp = timestamp + intervalDuration) { buckets.push(timestamp); } From 4cdf216260d9be36ef1d719b993c033fa2f45f68 Mon Sep 17 00:00:00 2001 From: palbizu <79482271+palbizu@users.noreply.github.com> Date: Mon, 2 Aug 2021 19:12:03 -0300 Subject: [PATCH 2/3] feat: Adding ticks count (#1046) * feat: adding tick days distance parameter in cartesian-axis * feat: Adding d3-time * feat: removing implicit dependencies * feat: removing implicit dependencies * feat: adding tick count * feat: fixing lintern * feat: fixing comment Co-authored-by: Patricio Albizu --- package.json | 1 + projects/observability/package.json | 3 ++- .../src/shared/components/cartesian/chart.ts | 6 ++++++ .../components/cartesian/d3/axis/cartesian-axis.ts | 9 +++++++-- 4 files changed, 16 insertions(+), 3 deletions(-) diff --git a/package.json b/package.json index 7eac08e1b..fbaa30728 100644 --- a/package.json +++ b/package.json @@ -56,6 +56,7 @@ "d3-scale": "^3.3.0", "d3-selection": "^1.4.2", "d3-shape": "^1.3.5", + "d3-time": "^2.1.1", "d3-transition": "^1.2.0", "d3-zoom": "^1.8.3", "graphql": "^15.5.1", diff --git a/projects/observability/package.json b/projects/observability/package.json index ae642db84..5d539eaba 100644 --- a/projects/observability/package.json +++ b/projects/observability/package.json @@ -29,7 +29,8 @@ "d3-path": "^1.0.9", "d3-hierarchy": "^1.1.9", "d3-axis": "^1.0.12", - "d3-quadtree": "^1.0.6" + "d3-quadtree": "^1.0.6", + "d3-time": "^2.1.1" }, "devDependencies": { "@hypertrace/test-utils": "^0.0.0" diff --git a/projects/observability/src/shared/components/cartesian/chart.ts b/projects/observability/src/shared/components/cartesian/chart.ts index 545ada8f5..aea7fc114 100644 --- a/projects/observability/src/shared/components/cartesian/chart.ts +++ b/projects/observability/src/shared/components/cartesian/chart.ts @@ -1,4 +1,5 @@ import { TimeRange } from '@hypertrace/common'; +import { TimeInterval } from 'd3-time'; import { LegendPosition } from '../legend/legend.component'; import { ChartTooltipRef } from '../utils/chart-tooltip/chart-tooltip-popover'; import { ChartEvent, ChartEventListener } from './chart-interactivty'; @@ -123,6 +124,11 @@ export interface Axis { * Maximum value of the axis. If unset, defaults to maximum value of provided data. */ max?: number; + + /** + * Determine the tick count labels (number or time interval) + */ + tickCount?: number | TimeInterval; } export interface AxisCrosshair { diff --git a/projects/observability/src/shared/components/cartesian/d3/axis/cartesian-axis.ts b/projects/observability/src/shared/components/cartesian/d3/axis/cartesian-axis.ts index 78f54a62e..8339838c7 100644 --- a/projects/observability/src/shared/components/cartesian/d3/axis/cartesian-axis.ts +++ b/projects/observability/src/shared/components/cartesian/d3/axis/cartesian-axis.ts @@ -1,5 +1,6 @@ import { Axis as D3Axis, axisBottom, AxisDomain, axisLeft, axisRight, AxisScale, axisTop } from 'd3-axis'; import { BaseType, select, Selection } from 'd3-selection'; +import { TimeInterval } from 'd3-time'; import { defaultsDeep } from 'lodash-es'; import { MouseLocationData } from '../../../utils/mouse-tracking/mouse-tracking'; import { SvgUtilService } from '../../../utils/svg/svg-util.service'; @@ -187,7 +188,11 @@ export class CartesianAxis { } } - private calculateAxisTickCount(): number { + private calculateAxisTickCount(): number | TimeInterval { + if (this.configuration?.tickCount !== undefined) { + return this.configuration.tickCount; + } + return 6; } @@ -235,4 +240,4 @@ export class CartesianAxis { } } -type DefaultedAxisConfig = Axis & Omit, 'scale' | 'crosshair' | 'min' | 'max'>; +type DefaultedAxisConfig = Axis & Omit, 'scale' | 'crosshair' | 'min' | 'max' | 'tickCount'>; From 53efba1a30b90c33ab8a1c9056b605033b2e8eff Mon Sep 17 00:00:00 2001 From: Aaron Steinfeld Date: Mon, 2 Aug 2021 18:40:36 -0400 Subject: [PATCH 3/3] chore: fixup --- .../cartesian/cartesian-chart.component.ts | 1 + ...xplore-cartesian-data-source.model.test.ts | 24 ++++++++++--------- ...zation-cartesian-data-source.model.test.ts | 24 ++++++++++--------- 3 files changed, 27 insertions(+), 22 deletions(-) diff --git a/projects/observability/src/shared/components/cartesian/cartesian-chart.component.ts b/projects/observability/src/shared/components/cartesian/cartesian-chart.component.ts index d825c2329..69c6c57dd 100644 --- a/projects/observability/src/shared/components/cartesian/cartesian-chart.component.ts +++ b/projects/observability/src/shared/components/cartesian/cartesian-chart.component.ts @@ -183,6 +183,7 @@ export class CartesianChartComponent implements OnChanges, OnDestroy { } const xValue = defaultXDataAccessor(location.dataPoint); const xAsDate = this.dateCoercer.coerce(xValue); + return xAsDate ? this.dateFormatter.format(xAsDate) : String(xValue); } } diff --git a/projects/observability/src/shared/dashboard/data/graphql/explore/explore-cartesian-data-source.model.test.ts b/projects/observability/src/shared/dashboard/data/graphql/explore/explore-cartesian-data-source.model.test.ts index 4183890d3..a34eeb8c8 100644 --- a/projects/observability/src/shared/dashboard/data/graphql/explore/explore-cartesian-data-source.model.test.ts +++ b/projects/observability/src/shared/dashboard/data/graphql/explore/explore-cartesian-data-source.model.test.ts @@ -28,8 +28,10 @@ import { ExploreCartesianDataSourceModel, ExplorerData } from './explore-cartesi describe('Explore cartesian data source model', () => { const testInterval = new TimeDuration(5, TimeUnit.Minute); - const endTime = new Date('2021-05-11T00:35:00.000Z'); - const startTime = new Date(endTime.getTime() - 2 * testInterval.toMillis()); + const startTime = new Date('2021-05-11T00:20:00.000Z'); + const firstIntervalTime = new Date(startTime.getTime() + testInterval.toMillis()); + const secondIntervalTime = new Date(startTime.getTime() + 2 * testInterval.toMillis()); + const endTime = new Date(startTime.getTime() + 3 * testInterval.toMillis()); const modelFactory = createModelFactory({ providers: [ @@ -108,7 +110,7 @@ describe('Explore cartesian data source model', () => { value: 15, type: AttributeMetadataType.Number }, - [GQL_EXPLORE_RESULT_INTERVAL_KEY]: endTime + [GQL_EXPLORE_RESULT_INTERVAL_KEY]: secondIntervalTime } ] }, @@ -127,11 +129,11 @@ describe('Explore cartesian data source model', () => { value: 10 }, { - timestamp: new Date('2021-05-11T00:30:00.000Z'), + timestamp: firstIntervalTime, value: 0 }, { - timestamp: endTime, + timestamp: secondIntervalTime, value: 15 } ] @@ -247,7 +249,7 @@ describe('Explore cartesian data source model', () => { value: 'first', type: AttributeMetadataType.String }, - [GQL_EXPLORE_RESULT_INTERVAL_KEY]: endTime + [GQL_EXPLORE_RESULT_INTERVAL_KEY]: secondIntervalTime }, { 'sum(foo)': { @@ -269,7 +271,7 @@ describe('Explore cartesian data source model', () => { value: 'second', type: AttributeMetadataType.String }, - [GQL_EXPLORE_RESULT_INTERVAL_KEY]: endTime + [GQL_EXPLORE_RESULT_INTERVAL_KEY]: secondIntervalTime } ] }, @@ -288,11 +290,11 @@ describe('Explore cartesian data source model', () => { value: 10 }, { - timestamp: new Date('2021-05-11T00:30:00.000Z'), + timestamp: firstIntervalTime, value: 0 }, { - timestamp: endTime, + timestamp: secondIntervalTime, value: 15 } ] @@ -307,11 +309,11 @@ describe('Explore cartesian data source model', () => { value: 20 }, { - timestamp: new Date('2021-05-11T00:30:00.000Z'), + timestamp: firstIntervalTime, value: 0 }, { - timestamp: endTime, + timestamp: secondIntervalTime, value: 25 } ] diff --git a/projects/observability/src/shared/dashboard/data/graphql/explorer-visualization/explorer-visualization-cartesian-data-source.model.test.ts b/projects/observability/src/shared/dashboard/data/graphql/explorer-visualization/explorer-visualization-cartesian-data-source.model.test.ts index 3ee0b4e5a..62860f475 100644 --- a/projects/observability/src/shared/dashboard/data/graphql/explorer-visualization/explorer-visualization-cartesian-data-source.model.test.ts +++ b/projects/observability/src/shared/dashboard/data/graphql/explorer-visualization/explorer-visualization-cartesian-data-source.model.test.ts @@ -26,8 +26,10 @@ import { ExplorerVisualizationCartesianDataSourceModel } from './explorer-visual describe('Explorer Visualization cartesian data source model', () => { const testInterval = new TimeDuration(5, TimeUnit.Minute); - const endTime = new Date('2021-05-11T00:35:00.000Z'); - const startTime = new Date(endTime.getTime() - 2 * testInterval.toMillis()); + const startTime = new Date('2021-05-11T00:20:00.000Z'); + const firstIntervalTime = new Date(startTime.getTime() + testInterval.toMillis()); + const secondIntervalTime = new Date(startTime.getTime() + 2 * testInterval.toMillis()); + const endTime = new Date(startTime.getTime() + 3 * testInterval.toMillis()); const modelFactory = createModelFactory({ providers: [ @@ -127,7 +129,7 @@ describe('Explorer Visualization cartesian data source model', () => { value: 15, type: AttributeMetadataType.Number }, - [GQL_EXPLORE_RESULT_INTERVAL_KEY]: endTime + [GQL_EXPLORE_RESULT_INTERVAL_KEY]: secondIntervalTime } ] }, @@ -146,11 +148,11 @@ describe('Explorer Visualization cartesian data source model', () => { value: 10 }, { - timestamp: new Date('2021-05-11T00:30:00.000Z'), + timestamp: firstIntervalTime, value: 0 }, { - timestamp: endTime, + timestamp: secondIntervalTime, value: 15 } ] @@ -269,7 +271,7 @@ describe('Explorer Visualization cartesian data source model', () => { value: 'first', type: AttributeMetadataType.String }, - [GQL_EXPLORE_RESULT_INTERVAL_KEY]: endTime + [GQL_EXPLORE_RESULT_INTERVAL_KEY]: secondIntervalTime }, { 'sum(foo)': { @@ -291,7 +293,7 @@ describe('Explorer Visualization cartesian data source model', () => { value: 'second', type: AttributeMetadataType.String }, - [GQL_EXPLORE_RESULT_INTERVAL_KEY]: endTime + [GQL_EXPLORE_RESULT_INTERVAL_KEY]: secondIntervalTime } ] }, @@ -310,11 +312,11 @@ describe('Explorer Visualization cartesian data source model', () => { value: 10 }, { - timestamp: new Date('2021-05-11T00:30:00.000Z'), + timestamp: firstIntervalTime, value: 0 }, { - timestamp: endTime, + timestamp: secondIntervalTime, value: 15 } ] @@ -329,11 +331,11 @@ describe('Explorer Visualization cartesian data source model', () => { value: 20 }, { - timestamp: new Date('2021-05-11T00:30:00.000Z'), + timestamp: firstIntervalTime, value: 0 }, { - timestamp: endTime, + timestamp: secondIntervalTime, value: 25 } ]