Skip to content

Commit

Permalink
✨ (line) make labels of focused entities bold
Browse files Browse the repository at this point in the history
  • Loading branch information
sophiamersmann committed Dec 11, 2024
1 parent 5c0dad9 commit 165e544
Showing 1 changed file with 87 additions and 36 deletions.
123 changes: 87 additions & 36 deletions packages/@ourworldindata/grapher/src/lineLegend/LineLegend.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -56,10 +56,11 @@ export interface LineLabelSeries extends ChartSeries {
}

interface SizedSeries extends LineLabelSeries {
textWrap: TextWrapGroup
textWrap: TextWrap | TextWrapGroup
annotationTextWrap?: TextWrap
width: number
height: number
fontWeight?: number
}

interface PlacedSeries extends SizedSeries {
Expand Down Expand Up @@ -162,7 +163,24 @@ class LineLabels extends React.Component<{
nonFocused && !hovered
? BACKGROUND_TEXT_COLOR
: darkenColorForText(series.color)
return (
return series.textWrap instanceof TextWrap ? (
<Halo
id={series.seriesName}
key={series.seriesName}
show={this.showTextOutline}
outlineColor={this.textOutlineColor}
>
{series.textWrap.render(labelText.x, labelText.y, {
textProps: {
fill: textColor,
opacity: this.textOpacityForSeries(series),
textAnchor: this.anchor,
// might override the textWrap's fontWeight
fontWeight: series.fontWeight,
},
})}
</Halo>
) : (
<React.Fragment key={series.seriesName}>
{series.textWrap.render(labelText.x, labelText.y, {
showTextOutline: this.showTextOutline,
Expand Down Expand Up @@ -381,52 +399,85 @@ export class LineLegend extends React.Component<LineLegendProps> {
return this.props.verticalAlign ?? VerticalAlign.middle
}

@computed.struct get sizedLabels(): SizedSeries[] {
const { fontSize, maxWidth } = this
const maxTextWidth = maxWidth - DEFAULT_CONNECTOR_LINE_WIDTH
const maxAnnotationWidth = Math.min(maxTextWidth, 150)
@computed private get textMaxWidth(): number {
return this.maxWidth - DEFAULT_CONNECTOR_LINE_WIDTH
}

private makeLabelTextWrap(
series: LineLabelSeries
): TextWrap | TextWrapGroup {
if (!series.formattedValue) {
return new TextWrap({
text: series.label,
maxWidth: this.textMaxWidth,
fontSize: this.fontSize,
// focused labels are bold while non-focused labels are regular.
// if we used the actual font-weights to compute the layout,
// the layout would be jumpy since different font weights lead
// to different text widths. that's why we always use bold labels
// for comupting the layout.
fontWeight: 700,
})
}

// text label fragment
const textLabel = { text: series.label, fontWeight: 700 }

// value label fragment
const newLine = series.placeFormattedValueInNewLine
? "always"
: "avoid-wrap"
const valueLabel = {
text: series.formattedValue,
fontWeight: 400,
newLine,
}

return new TextWrapGroup({
fragments: [textLabel, valueLabel],
maxWidth: this.textMaxWidth,
fontSize: this.fontSize,
})
}

private makeAnnotationTextWrap(
series: LineLabelSeries
): TextWrap | undefined {
if (!series.annotation) return undefined
const maxWidth = Math.min(this.textMaxWidth, 150)
return new TextWrap({
text: series.annotation,
maxWidth,
fontSize: this.fontSize * 0.9,
lineHeight: 1,
})
}

@computed.struct get sizedLabels(): SizedSeries[] {
const { fontWeight: globalFontWeight } = this
return this.props.labelSeries.map((label) => {
// if a formatted value is given, make the main label bold
const fontWeight = label.formattedValue ? 700 : this.fontWeight

const mainLabel = { text: label.label, fontWeight }
const valueLabel = label.formattedValue
? {
text: label.formattedValue,
newLine: (label.placeFormattedValueInNewLine
? "always"
: "avoid-wrap") as "always" | "avoid-wrap",
}
: undefined
const labelFragments = excludeUndefined([mainLabel, valueLabel])
const textWrap = new TextWrapGroup({
fragments: labelFragments,
maxWidth: maxTextWidth,
fontSize,
})
const annotationTextWrap = label.annotation
? new TextWrap({
text: label.annotation,
maxWidth: maxAnnotationWidth,
fontSize: fontSize * 0.9,
lineHeight: 1,
})
: undefined

const annotationWidth = annotationTextWrap
? annotationTextWrap.width
: 0
const textWrap = this.makeLabelTextWrap(label)
const annotationTextWrap = this.makeAnnotationTextWrap(label)

const annotationWidth = annotationTextWrap?.width ?? 0
const annotationHeight = annotationTextWrap
? ANNOTATION_PADDING + annotationTextWrap.height
: 0

// font weight priority:
// series focus state > globally set font weight > default font weight
const activeFontWeight = label.focus?.active ? 700 : undefined
const seriesFontWeight = label.formattedValue ? 700 : undefined
const fontWeight =
activeFontWeight ?? seriesFontWeight ?? globalFontWeight

return {
...label,
textWrap,
annotationTextWrap,
width: Math.max(textWrap.width, annotationWidth),
height: textWrap.height + annotationHeight,
fontWeight,
}
})
}
Expand Down

0 comments on commit 165e544

Please sign in to comment.