From 26ebe5ee71c948365af321251e27393eba079a70 Mon Sep 17 00:00:00 2001 From: alex Date: Wed, 14 Jul 2021 10:37:50 -0400 Subject: [PATCH] feat(heatmap): hard code x-axis labels sideways --- .../heatmap/layout/viewmodel/viewmodel.ts | 5 ++- .../renderer/canvas/canvas_renderers.ts | 3 +- .../state/selectors/get_grid_full_height.ts | 37 ++++++++++++++++--- stories/heatmap/1_basic.tsx | 7 ++-- 4 files changed, 40 insertions(+), 12 deletions(-) diff --git a/packages/charts/src/chart_types/heatmap/layout/viewmodel/viewmodel.ts b/packages/charts/src/chart_types/heatmap/layout/viewmodel/viewmodel.ts index f51b15f27f..b5e58d0d8a 100644 --- a/packages/charts/src/chart_types/heatmap/layout/viewmodel/viewmodel.ts +++ b/packages/charts/src/chart_types/heatmap/layout/viewmodel/viewmodel.ts @@ -68,14 +68,15 @@ function getValuesInRange( function getTicks(chartWidth: number, xAxisLabelConfig: Config['xAxisLabel']): number { const bboxCompute = new CanvasTextBBoxCalculator(); const labelSample = xAxisLabelConfig.formatter(Date.now()); - const { width } = bboxCompute.compute( + // TODO - use width or height depending on x axis tick label rotation + const { height } = bboxCompute.compute( labelSample, xAxisLabelConfig.padding, xAxisLabelConfig.fontSize, xAxisLabelConfig.fontFamily, ); bboxCompute.destroy(); - const maxTicks = Math.floor(chartWidth / width); + const maxTicks = Math.floor(chartWidth / height); // Dividing by 2 is a temp fix to make sure {@link ScaleContinuous} won't produce // to many ticks creating nice rounded tick values // TODO add support for limiting the number of tick in {@link ScaleContinuous} diff --git a/packages/charts/src/chart_types/heatmap/renderer/canvas/canvas_renderers.ts b/packages/charts/src/chart_types/heatmap/renderer/canvas/canvas_renderers.ts index e98b8730a1..be38fd7a17 100644 --- a/packages/charts/src/chart_types/heatmap/renderer/canvas/canvas_renderers.ts +++ b/packages/charts/src/chart_types/heatmap/renderer/canvas/canvas_renderers.ts @@ -161,7 +161,8 @@ export function renderCanvas2d( y: xValue.y, }, xValue.text, - config.xAxisLabel, + { ...config.xAxisLabel, align: 'left' }, + 90, ); }); }), diff --git a/packages/charts/src/chart_types/heatmap/state/selectors/get_grid_full_height.ts b/packages/charts/src/chart_types/heatmap/state/selectors/get_grid_full_height.ts index cf5c90886e..9d73359b03 100644 --- a/packages/charts/src/chart_types/heatmap/state/selectors/get_grid_full_height.ts +++ b/packages/charts/src/chart_types/heatmap/state/selectors/get_grid_full_height.ts @@ -17,11 +17,15 @@ * under the License. */ +import { max as d3Max } from 'd3-array'; + +import { Box, measureText } from '../../../../common/text_utils'; import { GlobalChartState } from '../../../../state/chart_state'; import { createCustomCachedSelector } from '../../../../state/create_selector'; import { getLegendSizeSelector } from '../../../../state/selectors/get_legend_size'; import { getSettingsSpecSelector } from '../../../../state/selectors/get_settings_specs'; import { isHorizontalLegend } from '../../../../utils/legend'; +// import { config } from '../../layout/config/config'; import { Config } from '../../layout/types/config_types'; import { getHeatmapConfigSelector } from './get_heatmap_config'; import { getHeatmapTableSelector } from './get_heatmap_table'; @@ -47,19 +51,40 @@ export const getGridHeightParamsSelector = createCustomCachedSelector( legendSize, { showLegend }, { height: containerHeight }, - { xAxisLabel: { padding, visible, fontSize }, grid, maxLegendHeight }, - { yValues }, + config, + // { xAxisLabel: { padding, visible, fontSize, formatter }, grid, maxLegendHeight }, + { table, yValues }, ): GridHeightParams => { - const xAxisHeight = visible ? fontSize : 0; - const totalVerticalPadding = padding * 2; + // where the x axis height gets taken into account + + // TODO - only do all of this when the x axis tick labels are rotated + const xValues = table.map((entry) => entry.x); + const formattedXValues = xValues.map(config.xAxisLabel.formatter); + const boxedXValues = formattedXValues.map((value) => { + return { + text: String(value), + value, + ...config.xAxisLabel, + }; + }); + // console.log('formattedXValues:', formattedXValues); + const textMeasurer = document.createElement('canvas'); + const textMeasurerCtx = textMeasurer.getContext('2d'); + const textMeasure = measureText(textMeasurerCtx!); + + const measuredXValues = textMeasure(config.xAxisLabel.fontSize, boxedXValues); + const xAxisHeightMeasured: number = d3Max(measuredXValues, ({ width }) => width) ?? 0; + // const xAxisHeight = visible ? fontSize : 0; + const xAxisHeight = config.xAxisLabel.visible ? xAxisHeightMeasured : 0; + const totalVerticalPadding = config.xAxisLabel.padding * 2; let legendHeight = 0; if (showLegend && isHorizontalLegend(legendSize.position)) { - legendHeight = maxLegendHeight ?? legendSize.height; + legendHeight = config.maxLegendHeight ?? legendSize.height; } const verticalRemainingSpace = containerHeight - xAxisHeight - totalVerticalPadding - legendHeight; // compute the grid cell height - const gridCellHeight = getGridCellHeight(yValues, grid, verticalRemainingSpace); + const gridCellHeight = getGridCellHeight(yValues, config.grid, verticalRemainingSpace); const height = gridCellHeight * yValues.length; const pageSize = diff --git a/stories/heatmap/1_basic.tsx b/stories/heatmap/1_basic.tsx index 46fec90f3d..0a57b2ab55 100644 --- a/stories/heatmap/1_basic.tsx +++ b/stories/heatmap/1_basic.tsx @@ -41,7 +41,7 @@ export const Example = () => { const persistCellsSelection = boolean('Persist cells selection', true); const debugState = boolean('Enable debug state', true); const dataStateAction = action('DataState'); - + const xAxisVisible = boolean('X Axis visible', true); const handler = useCallback(() => { setSelection(undefined); }, []); @@ -52,7 +52,7 @@ export const Example = () => { () => ({ grid: { cellHeight: { - min: 20, + min: 10, }, stroke: { width: 1, @@ -76,6 +76,7 @@ export const Example = () => { padding: { left: 10, right: 10 }, }, xAxisLabel: { + visible: xAxisVisible, formatter: (value: string | number) => { return niceTimeFormatter([1572825600000, 1572912000000])(value, { timeZone: 'UTC' }); }, @@ -84,7 +85,7 @@ export const Example = () => { setSelection({ x: e.x, y: e.y }); }) as Config['onBrushEnd'], }), - [], + [xAxisVisible], ); const logDebugstate = debounce(() => {