Skip to content
Snippets Groups Projects
Unverified Commit d819ee53 authored by Ryan Laurie's avatar Ryan Laurie Committed by GitHub
Browse files

Make text measurement function naming more consistent (#32086)

* create measureTextWidth functions

* update rowChart and utils

* update static viz
parent 1d688a5b
No related branches found
No related tags found
No related merge requests found
Showing
with 91 additions and 87 deletions
......@@ -23,3 +23,6 @@ export const measureText: TextMeasurer = (text: string, style: FontStyle) => {
textMetrics.actualBoundingBoxDescent,
};
};
export const measureTextWidth = (text: string, style: FontStyle) =>
measureText(text, style).width;
import { formatNumber } from "metabase/static-viz/lib/numbers";
import { measureText, measureTextHeight } from "metabase/static-viz/lib/text";
import {
measureTextWidth,
measureTextHeight,
} from "metabase/static-viz/lib/text";
import { FunnelDatum, FunnelSettings } from "../types";
export const calculateMargin = (
......@@ -27,9 +30,9 @@ export const calculateMargin = (
const left =
Math.max(
measureText(firstStep.toString(), stepFontSize),
measureText(formattedFirstMeasure, initialMeasureFontSize),
measureText(settings.step.name, nameFontSize),
measureTextWidth(firstStep.toString(), stepFontSize),
measureTextWidth(formattedFirstMeasure, initialMeasureFontSize),
measureTextWidth(settings.step.name, nameFontSize),
) + paddingLeft;
return {
......
import type { PieArcDatum } from "@visx/shape/lib/shapes/Pie";
import { NumberFormatOptions } from "metabase/static-viz/lib/numbers";
import { measureText } from "metabase/static-viz/lib/text";
import { measureTextWidth } from "metabase/static-viz/lib/text";
import {
GAUGE_ARC_ANGLE,
BASE_FONT_SIZE,
......@@ -54,7 +54,7 @@ export function getCirclePositionInSvgCoordinate(
export function calculateValueFontSize(displayValue: string, maxWidth: number) {
let dynamicValueFontSize = BASE_FONT_SIZE;
while (
measureText(displayValue, dynamicValueFontSize) >
measureTextWidth(displayValue, dynamicValueFontSize) >
2 * (maxWidth - VALUE_MARGIN)
) {
dynamicValueFontSize -= 1;
......@@ -91,7 +91,10 @@ export function calculateSegmentLabelTextAnchor(angle: number): TextAnchor {
export function calculateChartScale(gaugeLabels: GaugeLabelData[]) {
const gaugeLabelDimensions = gaugeLabels.map(gaugeLabel => {
const labelWidth = measureText(gaugeLabel.value, SEGMENT_LABEL_FONT_SIZE);
const labelWidth = measureTextWidth(
gaugeLabel.value,
SEGMENT_LABEL_FONT_SIZE,
);
return {
left:
......
import { measureText, truncateText } from "metabase/static-viz/lib/text";
import { measureTextWidth, truncateText } from "metabase/static-viz/lib/text";
import {
LEGEND_CIRCLE_MARGIN_RIGHT,
LEGEND_CIRCLE_SIZE,
......@@ -14,7 +14,7 @@ const calculateItemWidth = (
return (
LEGEND_CIRCLE_SIZE +
LEGEND_CIRCLE_MARGIN_RIGHT +
measureText(item.name, fontSize, fontWeight)
measureTextWidth(item.name, fontSize, fontWeight)
);
};
......
import Color from "color";
import { t } from "ttag";
import { measureText } from "metabase/static-viz/lib/text";
import { measureTextWidth } from "metabase/static-viz/lib/text";
import { ProgressBarData } from "./types";
const createPalette = (color: string) => ({
......@@ -42,7 +42,7 @@ export const calculatePointerLabelShift = (
pointerWidth: number,
fontSize: number,
) => {
const valueTextWidth = measureText(valueText, fontSize);
const valueTextWidth = measureTextWidth(valueText, fontSize);
const distanceToLeftBorder = pointerX - xMin;
const isCrossingLeftBorder = valueTextWidth / 2 > distanceToLeftBorder;
......
......@@ -2,9 +2,9 @@ import { Group } from "@visx/group";
import { RowChart } from "metabase/visualizations/shared/components/RowChart";
import type {
FontStyle,
TextMeasurer,
TextWidthMeasurer,
} from "metabase/visualizations/shared/types/measure-text";
import { measureText } from "metabase/static-viz/lib/text";
import { measureTextWidth } from "metabase/static-viz/lib/text";
import { getStackOffset } from "metabase/visualizations/lib/settings/stacking";
import {
getGroupedDataset,
......@@ -51,19 +51,16 @@ interface StaticRowChartProps {
getColor: ColorGetter;
}
const staticTextMeasurer: TextMeasurer = (text: string, style: FontStyle) => {
const textWidth = measureText(
const staticTextMeasurer: TextWidthMeasurer = (
text: string,
style: FontStyle,
) =>
measureTextWidth(
text,
parseInt(style.size.toString(), 10),
style.weight ? parseInt(style.weight.toString(), 10) : 400,
);
return {
width: textWidth,
height: -1, // this will be ignored by RowChart
};
};
const StaticRowChart = ({ data, settings, getColor }: StaticRowChartProps) => {
const remappedColumnsData = extractRemappedColumns(
data,
......@@ -129,7 +126,7 @@ const StaticRowChart = ({ data, settings, getColor }: StaticRowChartProps) => {
stackOffset={stackOffset}
tickFormatters={tickFormatters}
labelsFormatter={labelsFormatter}
measureText={staticTextMeasurer}
measureTextWidth={staticTextMeasurer}
xLabel={xLabel}
yLabel={yLabel}
hasXAxis={hasXAxis}
......
......@@ -29,7 +29,7 @@ import {
fixTimeseriesTicksExceedXTickCount,
} from "metabase/static-viz/components/XYChart/utils";
import { GoalLine } from "metabase/static-viz/components/XYChart/GoalLine";
import { measureText } from "metabase/static-viz/lib/text";
import { measureTextWidth } from "metabase/static-viz/lib/text";
import type {
Series,
......@@ -102,7 +102,10 @@ export const XYChart = ({
width,
height,
);
const VALUE_CHAR_SIZE = measureText("0", style.value?.fontSize as number);
const VALUE_CHAR_SIZE = measureTextWidth(
"0",
style.value?.fontSize as number,
);
const valuesLeftOffset = getValuesLeftOffset(
settings,
series,
......
......@@ -9,7 +9,7 @@ import {
NumberFormatOptions,
} from "metabase/static-viz/lib/numbers";
import {
measureText,
measureTextWidth,
measureTextHeight,
truncateText,
} from "metabase/static-viz/lib/text";
......@@ -83,7 +83,7 @@ export const getXTicksDimensions = (
.flatMap(s => s.data)
.map(datum => {
const tick = formatXTick(getX(datum), settings.type, settings.format);
return measureText(tick.toString(), fontSize);
return measureTextWidth(tick.toString(), fontSize);
})
.reduce((a, b) => Math.max(a, b), 0);
......@@ -137,7 +137,7 @@ export const calculateYTickWidth = (
) => {
const domainValuesWidths = domain
.map(value => formatNumber(value, settings))
.map(formatted => measureText(formatted, fontSize));
.map(formatted => measureTextWidth(formatted, fontSize));
return Math.max(...domainValuesWidths);
};
......
import type { TextProps } from "@visx/text";
import { measureText } from "metabase/static-viz/lib/text";
import { measureTextWidth } from "metabase/static-viz/lib/text";
import type { HydratedSeries } from "../types";
import { getY } from "./series";
......@@ -26,7 +26,7 @@ export function getValueStep(
const totalWidth = sample.reduce(
(sum, sampledData) =>
sum +
measureText(
measureTextWidth(
valueFormatter(getY(sampledData)),
valueProps.fontSize as number,
),
......
import { formatNumber } from "./numbers";
import { measureText } from "./text";
import { measureTextWidth } from "./text";
export const getXTickWidth = (data, accessors, maxWidth, fontSize) => {
return getXTickWidthFromValues(data.map(accessors.x), maxWidth, fontSize);
......@@ -8,7 +8,7 @@ export const getXTickWidth = (data, accessors, maxWidth, fontSize) => {
export const getXTickWidthFromValues = (values, maxWidth, fontSize) => {
const tickWidth = values
.map(tick => String(tick))
.map(tick => measureText(tick, fontSize))
.map(tick => measureTextWidth(tick, fontSize))
.reduce((a, b) => Math.max(a, b), 0);
return Math.min(tickWidth, maxWidth);
......@@ -18,7 +18,7 @@ export const getYTickWidth = (data, accessors, settings, fontSize) => {
return data
.map(accessors.y)
.map(tick => formatNumber(tick, settings?.y))
.map(tick => measureText(tick, fontSize))
.map(tick => measureTextWidth(tick, fontSize))
.reduce((a, b) => Math.max(a, b), 0);
};
......
......@@ -6,7 +6,7 @@ const DEFAULT_FONT_WEIGHT = 400;
export const { getTextWidth } = init(CHAR_SIZES);
export const measureText = (
export const measureTextWidth = (
text: string,
fontSize: number,
fontWeight = DEFAULT_FONT_WEIGHT,
......@@ -31,13 +31,13 @@ export const truncateText = (
fontSize: number,
fontWeight = DEFAULT_FONT_WEIGHT,
) => {
if (measureText(text, fontSize, fontWeight) <= width) {
if (measureTextWidth(text, fontSize, fontWeight) <= width) {
return text;
}
while (
text.length &&
measureText(text + CHAR_ELLIPSES, fontSize, fontWeight) > width
measureTextWidth(text + CHAR_ELLIPSES, fontSize, fontWeight) > width
) {
text = text.substring(0, text.length - 1).trim();
}
......
import { measureText, truncateText } from "./text";
import { measureTextWidth, truncateText } from "./text";
const fontSize = 11;
describe("measureText", () => {
describe("measureTextWidth", () => {
it("should measure text", () => {
expect(Math.round(measureText("abc", fontSize))).toBe(17);
expect(Math.round(measureTextWidth("abc", fontSize))).toBe(17);
});
});
......
import type { ComponentStory } from "@storybook/react";
import { measureText } from "metabase/lib/measure-text";
import { measureTextWidth } from "metabase/lib/measure-text";
import { getStaticChartTheme } from "metabase/static-viz/components/RowChart/theme";
import { color } from "metabase/lib/colors";
import { RowChart } from "./RowChart";
......@@ -72,7 +72,7 @@ Default.args = {
theme: getStaticChartTheme(color),
measureText,
measureTextWidth,
style: { fontFamily: "Lato" },
};
import { useMemo, useCallback } from "react";
import * as React from "react";
import { useMemo } from "react";
import type { NumberValue } from "d3-scale";
import type {
TextWidthMeasurer,
TextMeasurer,
} from "metabase/visualizations/shared/types/measure-text";
import type { TextWidthMeasurer } from "metabase/visualizations/shared/types/measure-text";
import { ChartTicksFormatters } from "metabase/visualizations/shared/types/format";
import { HoveredData } from "metabase/visualizations/shared/types/events";
import RowChartView, { RowChartViewProps } from "../RowChartView/RowChartView";
......@@ -51,7 +47,7 @@ export interface RowChartProps<TDatum> {
tickFormatters?: ChartTicksFormatters;
labelsFormatter?: (value: NumberValue) => string;
measureText: TextMeasurer;
measureTextWidth: TextWidthMeasurer;
xScaleType?: ContinuousScaleType;
......@@ -92,7 +88,7 @@ export const RowChart = <TDatum,>({
xScaleType = "linear",
measureText: measureTextSize,
measureTextWidth,
style,
......@@ -137,12 +133,6 @@ export const RowChart = <TDatum,>({
const { xTickFormatter, yTickFormatter } = tickFormatters;
// in this component, we expect a measurer that only measures width
const measureText: TextWidthMeasurer = useCallback(
(text, style) => measureTextSize(text, style)?.width,
[measureTextSize],
);
const margin = useMemo(
() =>
getChartMargin(
......@@ -151,7 +141,7 @@ export const RowChart = <TDatum,>({
theme.axis.ticks,
theme.axis.label,
goal != null,
measureText,
measureTextWidth,
xLabel,
yLabel,
hasXAxis,
......@@ -163,7 +153,7 @@ export const RowChart = <TDatum,>({
theme.axis.ticks,
theme.axis.label,
goal,
measureText,
measureTextWidth,
xLabel,
yLabel,
hasXAxis,
......@@ -207,7 +197,7 @@ export const RowChart = <TDatum,>({
? xScale
: addSideSpacingForTicksAndLabels(
xScale,
measureText,
measureTextWidth,
theme.axis.ticks,
xTickFormatter,
theme.dataLabels,
......@@ -216,7 +206,7 @@ export const RowChart = <TDatum,>({
),
[
labelsFormatter,
measureText,
measureTextWidth,
labelledSeries,
theme.axis.ticks,
theme.dataLabels,
......@@ -233,12 +223,12 @@ export const RowChart = <TDatum,>({
innerWidth,
paddedXScale,
xTickFormatter,
measureText,
measureTextWidth,
xScaleType,
),
[
innerWidth,
measureText,
measureTextWidth,
theme.axis.ticks,
paddedXScale,
xScaleType,
......@@ -247,8 +237,8 @@ export const RowChart = <TDatum,>({
);
const rowChartGoal = useMemo(
() => getRowChartGoal(goal, theme.goal, measureText, paddedXScale),
[goal, measureText, theme.goal, paddedXScale],
() => getRowChartGoal(goal, theme.goal, measureTextWidth, paddedXScale),
[goal, measureTextWidth, theme.goal, paddedXScale],
);
return (
......
import { render, screen } from "@testing-library/react";
import type { NumberValue } from "d3-scale";
import userEvent from "@testing-library/user-event";
import { measureText } from "metabase/lib/measure-text";
import { measureTextWidth } from "metabase/lib/measure-text";
import { ChartFont } from "../../types/style";
import type { RowChartTheme } from "./types";
......@@ -53,7 +53,7 @@ const defaultProps = {
},
theme,
stackOffset: null,
measureText,
measureTextWidth,
};
const setup = (props?: Partial<RowChartProps<TestDatum>>) => {
......
......@@ -16,11 +16,11 @@ const GOAL_LINE_PADDING = 14;
export const getMaxWidth = (
formattedYTicks: string[],
ticksFont: ChartFont,
measureText: TextWidthMeasurer,
measureTextWidth: TextWidthMeasurer,
): number => {
return Math.max(
...formattedYTicks.map(tick =>
measureText(tick, {
measureTextWidth(tick, {
size: `${ticksFont.size}px`,
family: "Lato",
weight: String(ticksFont.weight ?? 400),
......@@ -35,7 +35,7 @@ export const getChartMargin = <TDatum>(
ticksFont: ChartFont,
labelFont: ChartFont,
hasGoalLine: boolean,
measureText: TextWidthMeasurer,
measureTextWidth: TextWidthMeasurer,
xLabel?: string | null,
yLabel?: string | null,
hasXAxis?: boolean,
......@@ -47,7 +47,7 @@ export const getChartMargin = <TDatum>(
seriesData.bars.map(bar => yTickFormatter(bar.yValue)),
),
ticksFont,
measureText,
measureTextWidth,
) + TICKS_OFFSET
: 0;
......@@ -83,14 +83,14 @@ export const getMaxYValuesCount = (
export const getRowChartGoal = (
goal: ChartGoal | null | undefined,
style: GoalStyle,
measureText: TextWidthMeasurer,
measureTextWidth: TextWidthMeasurer,
xScale: ScaleContinuousNumeric<number, number, never>,
) => {
if (!goal) {
return null;
}
const labelWidth = measureText(goal.label, style.label);
const labelWidth = measureTextWidth(goal.label, style.label);
const goalX = xScale(goal.value);
const xMax = xScale.range()[1];
const availableRightSideSpace = xMax - goalX;
......
......@@ -100,7 +100,7 @@ const getTickInfo = (
tickX: number,
tickFormatter: ValueFormatter,
tickFont: ChartFont,
measureText: TextWidthMeasurer,
measureTextWidth: TextWidthMeasurer,
xScale: ScaleContinuousNumeric<number, number, never>,
) => {
const value = xScale.invert(tickX);
......@@ -109,7 +109,7 @@ const getTickInfo = (
value,
tickX,
formatted: tickFormatter(value),
tickWidth: measureText(tickFormatter(value), tickFont),
tickWidth: measureTextWidth(tickFormatter(value), tickFont),
};
};
......@@ -117,7 +117,7 @@ const Y_AXIS_LEFT_PADDING = 16;
export const addSideSpacingForTicksAndLabels = (
xScale: ScaleContinuousNumeric<number, number, never>,
measureText: TextWidthMeasurer,
measureTextWidth: TextWidthMeasurer,
tickFont: ChartFont,
tickFormatter: ValueFormatter,
labelFont: ChartFont,
......@@ -132,7 +132,7 @@ export const addSideSpacingForTicksAndLabels = (
rangeMin,
tickFormatter,
tickFont,
measureText,
measureTextWidth,
xScale,
);
......@@ -141,7 +141,7 @@ export const addSideSpacingForTicksAndLabels = (
const leftLabelOverflow = shouldShowLabels
? rangeMin -
(xScale(domainMin) -
measureText(labelFormatter(domainMin), labelFont) -
measureTextWidth(labelFormatter(domainMin), labelFont) -
DATA_LABEL_OFFSET * 2 -
Y_AXIS_LEFT_PADDING)
: 0;
......@@ -153,13 +153,13 @@ export const addSideSpacingForTicksAndLabels = (
rangeMax,
tickFormatter,
tickFont,
measureText,
measureTextWidth,
xScale,
);
const maxTickOverflow = maxTick.tickX + maxTick.tickWidth / 2 - rangeMax;
const rightLabelOverflow = shouldShowLabels
? xScale(domainMax) +
measureText(labelFormatter(domainMax), labelFont) +
measureTextWidth(labelFormatter(domainMax), labelFont) +
DATA_LABEL_OFFSET -
rangeMax
: 0;
......
......@@ -14,7 +14,7 @@ const omitOverlappingTicks = (
tickFont: ChartFont,
xScale: ScaleContinuousNumeric<number, number, never>,
tickFormatter: ValueFormatter,
measureText: TextWidthMeasurer,
measureTextWidth: TextWidthMeasurer,
) => {
if (ticks.length <= 1) {
return ticks;
......@@ -27,7 +27,10 @@ const omitOverlappingTicks = (
for (let i = ticks.length - 1; i >= 0; i--) {
const currentTick = ticks[i];
const currentTickWidth = measureText(tickFormatter(currentTick), tickFont);
const currentTickWidth = measureTextWidth(
tickFormatter(currentTick),
tickFont,
);
const currentTickX = xScale(currentTick);
const currentTickEnd = currentTickX + currentTickWidth / 2;
......@@ -47,14 +50,16 @@ const omitOverlappingTicks = (
const getMaxTickWidth = (
scale: ScaleContinuousNumeric<number, number, never>,
measureText: TextWidthMeasurer,
measureTextWidth: TextWidthMeasurer,
tickFormatter: ValueFormatter,
tickFont: ChartFont,
) => {
// Assume border ticks on a continuous scale are the widest
const borderTicksWidths = scale
.domain()
.map(tick => measureText(tickFormatter(tick), tickFont) + TICK_SPACING);
.map(
tick => measureTextWidth(tickFormatter(tick), tickFont) + TICK_SPACING,
);
return Math.max(...borderTicksWidths);
};
......@@ -111,12 +116,12 @@ export const getXTicks = (
innerWidth: number,
xScale: ScaleContinuousNumeric<number, number, never>,
tickFormatter: ValueFormatter,
measureText: TextWidthMeasurer,
measureTextWidth: TextWidthMeasurer,
scaleType: ContinuousScaleType,
) => {
const ticksInterval = getMinTicksInterval(
xScale,
measureText,
measureTextWidth,
tickFormatter,
tickFont,
innerWidth,
......@@ -134,6 +139,6 @@ export const getXTicks = (
tickFont,
xScale,
tickFormatter,
measureText,
measureTextWidth,
);
};
......@@ -10,7 +10,7 @@ import {
getChartColumns,
hasValidColumnsSelected,
} from "metabase/visualizations/lib/graph/columns";
import { measureText } from "metabase/lib/measure-text";
import { measureTextWidth } from "metabase/lib/measure-text";
import ExplicitSize from "metabase/components/ExplicitSize";
import {
getClickData,
......@@ -270,7 +270,7 @@ const RowChartVisualization = ({
const textMeasurer = useMemo(() => {
return (text: string, style: FontStyle) =>
measureText(text, {
measureTextWidth(text, {
...style,
family: fontFamily,
});
......@@ -309,7 +309,7 @@ const RowChartVisualization = ({
stackOffset={stackOffset}
tickFormatters={tickFormatters}
labelsFormatter={labelsFormatter}
measureText={textMeasurer}
measureTextWidth={textMeasurer}
hoveredData={hoverData}
onClick={handleClick}
onHover={handleHover}
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment