Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor: DRY up measureText code #1535

Merged
merged 15 commits into from
Dec 24, 2021
Merged
Prev Previous commit
Next Next commit
Use cssFontShorthand and actualBoundingBox on textMeasure
markov00 committed Dec 22, 2021

Verified

This commit was signed with the committer’s verified signature.
MGatner MGatner
commit 615b01b337e7fdf69afe52d14cc3d3fb4056fad2
Original file line number Diff line number Diff line change
@@ -56,12 +56,12 @@ function getValuesInRange(
function estimatedNonOverlappingTickCount(
chartWidth: number,
formatter: HeatmapSpec['xAxisLabelFormatter'],
{ padding, fontSize, fontFamily }: HeatmapStyle['xAxisLabel'],
style: HeatmapStyle['xAxisLabel'],
): number {
return withTextMeasure((textMeasure) => {
const labelSample = formatter(Date.now());
const { width } = textMeasure(labelSample, horizontalPad(padding), fontSize, fontFamily);
const maxTicks = chartWidth / width;
const { width } = textMeasure(labelSample, { ...style }, style.fontSize);
monfera marked this conversation as resolved.
Show resolved Hide resolved
const maxTicks = chartWidth / (width + horizontalPad(style.padding));
// 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}
Original file line number Diff line number Diff line change
@@ -21,19 +21,11 @@ import { getHeatmapTableSelector } from './get_heatmap_table';
*/
export const getXAxisRightOverflow = createCustomCachedSelector(
[getHeatmapSpecSelector, getChartThemeSelector, getHeatmapTableSelector],
(
{ xScale, timeZone, xAxisLabelFormatter },
{
heatmap: {
xAxisLabel: { fontSize, fontFamily, padding, width },
},
},
{ xNumericExtent },
) => {
({ xScale, timeZone, xAxisLabelFormatter }, { heatmap: { xAxisLabel: style } }, { xNumericExtent }) => {
return xScale.type !== ScaleType.Time
? 0
: typeof width === 'number'
? width / 2
: typeof style.width === 'number'
? style.width / 2
: withTextMeasure((measure) => {
return new ScaleContinuous(
{ type: ScaleType.Time, domain: xNumericExtent, range: [0, 1] },
@@ -42,7 +34,10 @@ export const getXAxisRightOverflow = createCustomCachedSelector(
.ticks()
.reduce(
(max, n) =>
Math.max(max, measure(xAxisLabelFormatter(n), horizontalPad(padding), fontSize, fontFamily).width),
Math.max(
max,
measure(xAxisLabelFormatter(n), { ...style }, style.fontSize).width + horizontalPad(style.padding),
),
0,
);
}) / 2;
8 changes: 6 additions & 2 deletions packages/charts/src/chart_types/xy_chart/rendering/bars.ts
Original file line number Diff line number Diff line change
@@ -180,11 +180,15 @@ function computeBoxWidth(
): { fixedFontScale: number; displayValueWidth: number } {
const fixedFontScale = Math.max(typeof fontSize === 'number' ? fontSize : fontSize.min, 1);

const computedDisplayValueWidth = textMeasure(text || '', padding, fixedFontScale, fontFamily).width;
const computedDisplayValueWidth = textMeasure(
text || '',
monfera marked this conversation as resolved.
Show resolved Hide resolved
{ fontFamily, fontWeight: 'normal', fontStyle: 'normal', fontVariant: 'normal' },
fixedFontScale,
).width;
if (typeof fontSize !== 'number') {
return {
fixedFontScale,
displayValueWidth: computedDisplayValueWidth,
displayValueWidth: computedDisplayValueWidth + padding,
};
}
return {
Original file line number Diff line number Diff line change
@@ -116,7 +116,16 @@ export const getLabelBox = (
): TickLabelBounds => ({
...(axesStyle.tickLabel.visible ? ticks.map(labelFormatter) : []).reduce(
(sizes, labelText) => {
const bbox = textMeasure(labelText, 0, axesStyle.tickLabel.fontSize, axesStyle.tickLabel.fontFamily);
const bbox = textMeasure(
labelText,
{
fontStyle: axesStyle.tickLabel.fontStyle ?? 'normal',
fontFamily: axesStyle.tickLabel.fontFamily,
fontWeight: 'normal',
fontVariant: 'normal',
},
axesStyle.tickLabel.fontSize,
);
const rotatedBbox = computeRotatedLabelDimensions(bbox, axesStyle.tickLabel.rotation);
sizes.maxLabelBboxWidth = Math.max(sizes.maxLabelBboxWidth, Math.ceil(rotatedBbox.width));
sizes.maxLabelBboxHeight = Math.max(sizes.maxLabelBboxHeight, Math.ceil(rotatedBbox.height));
7 changes: 6 additions & 1 deletion packages/charts/src/state/selectors/get_legend_size.ts
Original file line number Diff line number Diff line change
@@ -45,7 +45,12 @@ export const getLegendSizeSelector = createCustomCachedSelector(
const bbox = withTextMeasure((textMeasure) =>
labels.reduce(
(acc, { label, depth }) => {
const { width, height } = textMeasure(label, 1, 12, MAGIC_FONT_FAMILY, 1.5, 400);
const { width, height } = textMeasure(
label,
{ fontFamily: MAGIC_FONT_FAMILY, fontVariant: 'normal', fontWeight: 400, fontStyle: 'normal' },
monfera marked this conversation as resolved.
Show resolved Hide resolved
12,
1.5,
);
acc.width = Math.max(acc.width, width + depth * LEGEND_HIERARCHY_MARGIN);
acc.height = Math.max(acc.height, height);
return acc;
18 changes: 6 additions & 12 deletions packages/charts/src/utils/bbox/canvas_text_bbox_calculator.ts
Original file line number Diff line number Diff line change
@@ -6,28 +6,22 @@
* Side Public License, v 1.
*/

import { cssFontShorthand, Font } from '../../common/text_utils';
import { Size } from '../dimensions';

/** @internal */
export type TextMeasure = (
text: string,
padding: number,
fontSize: number,
fontFamily: string,
lineHeight?: number,
fontWeight?: number,
) => Size;
export type TextMeasure = (text: string, font: Omit<Font, 'textColor'>, fontSize: number, lineHeight?: number) => Size;

/** @internal */
export const withTextMeasure = <T>(fun: (textMeasure: TextMeasure) => T) => {
const canvas = document.createElement('canvas');
const ctx = canvas.getContext('2d');
return fun(
ctx
? (text: string, padding: number, fontSize, fontFamily, lineHeight = 1, fontWeight = 400) => {
ctx.font = `${fontWeight} ${fontSize}px ${fontFamily}`;
const measure = ctx.measureText(text);
return { width: measure.width + Math.max(padding, 1), height: fontSize * lineHeight };
? (text, font, fontSize, lineHeight = 1) => {
ctx.font = cssFontShorthand(font, fontSize);
const { actualBoundingBoxLeft, actualBoundingBoxRight } = ctx.measureText(text);
return { width: actualBoundingBoxLeft + actualBoundingBoxRight, height: fontSize * lineHeight };
}
: () => ({ width: 0, height: 0 }),
);