Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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.
15 changes: 15 additions & 0 deletions e2e/tests/test_cases_stories.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -179,4 +179,19 @@ test.describe('Test cases stories', () => {
);
});
});

test('should render font measurement test story', async ({ page }) => {
await common.expectElementAtUrlToMatchScreenshot(page)(
'http://localhost:9001/?path=/story/test-cases--font-measurement-test',
'#story-root',
{
waitSelector: common.chartWaitSelector,
action: async () => {
await page.waitForFunction(() => {
return document.querySelectorAll('.echChartStatus[data-ech-render-complete="true"]').length >= 4;
});
},
},
);
});
});
2 changes: 2 additions & 0 deletions packages/charts/api/charts.api.md
Original file line number Diff line number Diff line change
Expand Up @@ -567,6 +567,8 @@ export interface BulletStyle {
// (undocumented)
fallbackBandColor: Color;
// (undocumented)
fontFamily: string;
// (undocumented)
minHeight: Pixels;
// (undocumented)
nonFiniteText: string;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,14 +22,14 @@ import type { BulletStyle } from '../../theme';
import {
FONT_PADDING,
HEADER_PADDING,
SUBTITLE_FONT,
getSubtitleFont,
getTargetFont,
getTitleFont,
getValueFont,
SUBTITLE_FONT_SIZE,
TARGET_FONT,
TARGET_FONT_SIZE,
TITLE_FONT,
TITLE_FONT_SIZE,
TITLE_LINE_SPACING,
VALUE_FONT,
VALUE_FONT_SIZE,
getMaxTargetValueAssent,
getTextAscentHeight,
Expand All @@ -51,6 +51,11 @@ export function renderBullet(
) {
const { debug, style, dimensions, activeValues, spec, backgroundColor } = props;
withContext(ctx, (ctx) => {
const titleFont = getTitleFont(style.fontFamily);
const subtitleFont = getSubtitleFont(style.fontFamily);
const valueFont = getValueFont(style.fontFamily);
const targetFont = getTargetFont(style.fontFamily);

ctx.scale(dpr, dpr);
clearCanvas(ctx, backgroundColor);

Expand Down Expand Up @@ -112,7 +117,7 @@ export function renderBullet(
// Title
ctx.fillStyle = props.style.textColor;
ctx.textAlign = 'start';
ctx.font = cssFontShorthand(TITLE_FONT, TITLE_FONT_SIZE);
ctx.font = cssFontShorthand(titleFont, TITLE_FONT_SIZE);

const titleYBaseline =
commonYBaseline -
Expand All @@ -129,12 +134,12 @@ export function renderBullet(

// Subtitle
if (bulletGraph.subtitle) {
ctx.font = cssFontShorthand(SUBTITLE_FONT, SUBTITLE_FONT_SIZE);
ctx.font = cssFontShorthand(subtitleFont, SUBTITLE_FONT_SIZE);
ctx.fillText(bulletGraph.subtitle, 0, commonYBaseline);
}

// Value
ctx.font = cssFontShorthand(VALUE_FONT, VALUE_FONT_SIZE);
ctx.font = cssFontShorthand(valueFont, VALUE_FONT_SIZE);
if (!multiline) ctx.textAlign = 'end';
{
const y = commonYBaseline + (multiline ? MAX_TARGET_VALUE_ASCENT + FONT_PADDING : 0);
Expand All @@ -145,7 +150,7 @@ export function renderBullet(

// Target
if (bulletGraph.target) {
ctx.font = cssFontShorthand(TARGET_FONT, TARGET_FONT_SIZE);
ctx.font = cssFontShorthand(targetFont, TARGET_FONT_SIZE);
if (!multiline) ctx.textAlign = 'end';
const x = multiline ? bulletGraph.valueWidth : bulletGraph.header.width;
const y = commonYBaseline + (multiline ? MAX_TARGET_VALUE_ASCENT + FONT_PADDING : 0);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ import type { BulletPanelDimensions } from '../../../selectors/get_panel_dimensi
import type { BulletSpec } from '../../../spec';
import { BulletSubtype } from '../../../spec';
import type { BulletStyle } from '../../../theme';
import { GRAPH_PADDING, TICK_FONT, TICK_FONT_SIZE } from '../../../theme';
import { GRAPH_PADDING, TICK_FONT_SIZE, getTickFont } from '../../../theme';
import { getAngledChartSizing } from '../../../utils/angular';
import { TARGET_SIZE, BULLET_SIZE, TICK_WIDTH, BAR_SIZE, TARGET_STROKE_WIDTH } from '../constants';

Expand All @@ -32,6 +32,7 @@ export function angularBullet(
debug: boolean,
activeValue?: ActiveValue | null,
) {
const tickFont = getTickFont(style.fontFamily);
const { datum, graphArea, scale, ticks, colorBands } = dimensions;
const { radius } = getAngledChartSizing(graphArea.size, spec.subtype);
const [startAngle, endAngle] = scale.range() as [number, number];
Expand Down Expand Up @@ -119,14 +120,14 @@ export function angularBullet(
const measure = measureText(ctx);
// Assumes mostly homogenous formatting
const maxTickWidth = formatterColorTicks.reduce((acc, t) => {
const { width } = measure(t.formattedValue, TICK_FONT, TICK_FONT_SIZE);
const { width } = measure(t.formattedValue, tickFont, TICK_FONT_SIZE);
return Math.max(acc, width);
}, 0);

// Tick labels
ctx.fillStyle = style.textColor;
ctx.textBaseline = 'middle';
ctx.font = cssFontShorthand(TICK_FONT, TICK_FONT_SIZE);
ctx.font = cssFontShorthand(tickFont, TICK_FONT_SIZE);
formatterColorTicks
.filter((tick) => tick.value >= min && tick.value <= max)
.forEach((tick) => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import type { ContinuousDomain, GenericDomain } from '../../../../../utils/domai
import type { ActiveValue } from '../../../selectors/get_active_values';
import type { BulletPanelDimensions } from '../../../selectors/get_panel_dimensions';
import type { BulletStyle } from '../../../theme';
import { GRAPH_PADDING, TICK_FONT, TICK_FONT_SIZE } from '../../../theme';
import { GRAPH_PADDING, TICK_FONT_SIZE, getTickFont } from '../../../theme';
import { TARGET_SIZE, BULLET_SIZE, TICK_WIDTH, BAR_SIZE, TARGET_STROKE_WIDTH, TICK_LABEL_PADDING } from '../constants';

/** @internal */
Expand All @@ -25,6 +25,7 @@ export function horizontalBullet(
backgroundColor: Color,
activeValue?: ActiveValue | null,
) {
const tickFont = getTickFont(style.fontFamily);
ctx.translate(GRAPH_PADDING.left, 0);

const { datum, colorBands, ticks, scale } = dimensions;
Expand Down Expand Up @@ -89,14 +90,14 @@ export function horizontalBullet(
// Tick labels
ctx.fillStyle = style.textColor;
ctx.textBaseline = 'top';
ctx.font = cssFontShorthand(TICK_FONT, TICK_FONT_SIZE);
ctx.font = cssFontShorthand(tickFont, TICK_FONT_SIZE);
ticks
.filter((tick) => tick >= min && tick <= max)
.forEach((tick, i) => {
const labelText = datum.tickFormatter(tick);
if (i === ticks.length - 1) {
const availableWidth = Math.abs((start > end ? min : max) - (ticks.at(i) ?? NaN));
const { width: labelWidth } = measureText(ctx)(labelText, TICK_FONT, TICK_FONT_SIZE);
const { width: labelWidth } = measureText(ctx)(labelText, tickFont, TICK_FONT_SIZE);
ctx.textAlign = labelWidth >= Math.abs(scale(availableWidth) - scale(0)) ? 'end' : 'start';
} else {
ctx.textAlign = 'start';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import type { ContinuousDomain, GenericDomain } from '../../../../../utils/domai
import type { ActiveValue } from '../../../selectors/get_active_values';
import type { BulletPanelDimensions } from '../../../selectors/get_panel_dimensions';
import type { BulletStyle } from '../../../theme';
import { GRAPH_PADDING, TICK_FONT, TICK_FONT_SIZE } from '../../../theme';
import { GRAPH_PADDING, TICK_FONT_SIZE, getTickFont } from '../../../theme';
import { TARGET_SIZE, BULLET_SIZE, TICK_WIDTH, BAR_SIZE, TARGET_STROKE_WIDTH, TICK_LABEL_PADDING } from '../constants';

/** @internal */
Expand All @@ -24,6 +24,7 @@ export function verticalBullet(
backgroundColor: Color,
activeValue?: ActiveValue | null,
) {
const tickFont = getTickFont(style.fontFamily);
ctx.translate(0, GRAPH_PADDING.top);

const { datum, graphArea, scale, colorBands, ticks } = dimensions;
Expand Down Expand Up @@ -99,7 +100,7 @@ export function verticalBullet(
// Tick labels
ctx.textBaseline = 'top';
ctx.fillStyle = style.textColor;
ctx.font = cssFontShorthand(TICK_FONT, TICK_FONT_SIZE);
ctx.font = cssFontShorthand(tickFont, TICK_FONT_SIZE);
ticks
.filter((tick) => tick >= min && tick <= max)
.forEach((tick, i) => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
import { getBulletSpec } from './get_bullet_spec';
import { getChartSize } from './get_chart_size';
import { createCustomCachedSelector } from '../../../state/create_selector';
import { getChartThemeSelector } from '../../../state/selectors/get_chart_theme';
import { getSettingsSpecSelector } from '../../../state/selectors/get_settings_spec';
import { withTextMeasure } from '../../../utils/bbox/canvas_text_bbox_calculator';
import type { Size } from '../../../utils/dimensions';
Expand All @@ -18,14 +19,14 @@ import type { BulletDatum } from '../spec';
import {
FONT_PADDING,
HEADER_PADDING,
SUBTITLE_FONT,
getSubtitleFont,
getTargetFont,
getTitleFont,
getValueFont,
SUBTITLE_FONT_SIZE,
TARGET_FONT,
TARGET_FONT_SIZE,
TITLE_FONT,
TITLE_FONT_SIZE,
TITLE_LINE_SPACING,
VALUE_FONT,
VALUE_FONT_SIZE,
getMaxTargetValueAssent,
getTextAscentHeight,
Expand Down Expand Up @@ -83,8 +84,8 @@ const minChartWidths: Record<BulletSubtype, number> = {

/** @internal */
export const getLayout = createCustomCachedSelector(
[getBulletSpec, getChartSize, getSettingsSpecSelector],
(spec, chartSize, { locale }): BulletLayout => {
[getBulletSpec, getChartSize, getSettingsSpecSelector, getChartThemeSelector],
(spec, chartSize, { locale }, { bulletGraph }): BulletLayout => {
const { data } = spec;
const rows = data.length;
const columns = data.reduce((acc, row) => {
Expand All @@ -97,6 +98,11 @@ export const getLayout = createCustomCachedSelector(
height: panel.height - HEADER_PADDING.top - HEADER_PADDING.bottom,
};

const titleFont = getTitleFont(bulletGraph.fontFamily);
const subtitleFont = getSubtitleFont(bulletGraph.fontFamily);
const valueFont = getValueFont(bulletGraph.fontFamily);
const targetFont = getTargetFont(bulletGraph.fontFamily);

return withTextMeasure((textMeasurer) => {
// collect header elements title, subtitles and values
const header = data.map((row) =>
Expand All @@ -111,10 +117,10 @@ export const getLayout = createCustomCachedSelector(
datum: cell,
};
const widths = {
title: textMeasurer(content.title.trim(), TITLE_FONT, TITLE_FONT_SIZE).width,
subtitle: content.subtitle ? textMeasurer(content.subtitle, TITLE_FONT, TITLE_FONT_SIZE).width : 0,
value: textMeasurer(content.value, VALUE_FONT, VALUE_FONT_SIZE).width,
target: textMeasurer(content.target, TARGET_FONT, TARGET_FONT_SIZE).width,
title: textMeasurer(content.title.trim(), titleFont, TITLE_FONT_SIZE).width,
subtitle: content.subtitle ? textMeasurer(content.subtitle, subtitleFont, SUBTITLE_FONT_SIZE).width : 0,
value: textMeasurer(content.value, valueFont, VALUE_FONT_SIZE).width,
target: textMeasurer(content.target, targetFont, TARGET_FONT_SIZE).width,
};
return { content, widths };
}),
Expand All @@ -135,23 +141,16 @@ export const getLayout = createCustomCachedSelector(

const titleTruncated = wrapText(
cell.content.title,
TITLE_FONT,
titleFont,
TITLE_FONT_SIZE,
availableWidth,
2,
textMeasurer,
locale,
).meta.truncated;
const subtitleTruncated = cell.content.subtitle
? wrapText(
cell.content.subtitle,
SUBTITLE_FONT,
SUBTITLE_FONT_SIZE,
availableWidth,
1,
textMeasurer,
locale,
).meta.truncated
? wrapText(cell.content.subtitle, subtitleFont, SUBTITLE_FONT_SIZE, availableWidth, 1, textMeasurer, locale)
.meta.truncated
: false;

return titleTruncated || subtitleTruncated;
Expand All @@ -172,7 +171,7 @@ export const getLayout = createCustomCachedSelector(
// wrap only title if necessary
title: wrapText(
cell.content.title,
TITLE_FONT,
titleFont,
TITLE_FONT_SIZE,
headerSize.width,
2,
Expand All @@ -182,7 +181,7 @@ export const getLayout = createCustomCachedSelector(
subtitle: cell.content.subtitle
? wrapText(
cell.content.subtitle,
SUBTITLE_FONT,
subtitleFont,
SUBTITLE_FONT_SIZE,
headerSize.width,
1,
Expand All @@ -203,11 +202,11 @@ export const getLayout = createCustomCachedSelector(
return {
panel,
header: headerSize,
title: wrapText(cell.content.title, TITLE_FONT, TITLE_FONT_SIZE, availableWidth, 2, textMeasurer, locale),
title: wrapText(cell.content.title, titleFont, TITLE_FONT_SIZE, availableWidth, 2, textMeasurer, locale),
subtitle: cell.content.subtitle
? wrapText(
cell.content.subtitle,
SUBTITLE_FONT,
subtitleFont,
SUBTITLE_FONT_SIZE,
availableWidth,
1,
Expand Down
Loading