Skip to content

Commit a09684a

Browse files
✨ (line) make labels of focused entities bold
1 parent ce475d9 commit a09684a

File tree

1 file changed

+87
-37
lines changed

1 file changed

+87
-37
lines changed

packages/@ourworldindata/grapher/src/lineLegend/LineLegend.tsx

Lines changed: 87 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -56,10 +56,11 @@ export interface LineLabelSeries extends ChartSeries {
5656
}
5757

5858
interface SizedSeries extends LineLabelSeries {
59-
textWrap: TextWrapGroup
59+
textWrap: TextWrap | TextWrapGroup
6060
annotationTextWrap?: TextWrap
6161
width: number
6262
height: number
63+
fontWeight?: number
6364
}
6465

6566
interface PlacedSeries extends SizedSeries {
@@ -162,7 +163,24 @@ class LineLabels extends React.Component<{
162163
nonFocused && !hovered
163164
? BACKGROUND_TEXT_COLOR
164165
: darkenColorForText(series.color)
165-
return (
166+
return series.textWrap instanceof TextWrap ? (
167+
<Halo
168+
id={series.seriesName}
169+
key={series.seriesName}
170+
show={this.showTextOutline}
171+
outlineColor={this.textOutlineColor}
172+
>
173+
{series.textWrap.render(labelText.x, labelText.y, {
174+
textProps: {
175+
fill: textColor,
176+
opacity: this.textOpacityForSeries(series),
177+
textAnchor: this.anchor,
178+
// might override the textWrap's fontWeight
179+
fontWeight: series.fontWeight,
180+
},
181+
})}
182+
</Halo>
183+
) : (
166184
<React.Fragment key={series.seriesName}>
167185
{series.textWrap.render(labelText.x, labelText.y, {
168186
showTextOutline: this.showTextOutline,
@@ -381,53 +399,85 @@ export class LineLegend extends React.Component<LineLegendProps> {
381399
return this.props.verticalAlign ?? VerticalAlign.middle
382400
}
383401

384-
@computed.struct get sizedLabels(): SizedSeries[] {
385-
const { fontSize, maxWidth } = this
386-
const maxTextWidth = maxWidth - DEFAULT_CONNECTOR_LINE_WIDTH
387-
const maxAnnotationWidth = Math.min(maxTextWidth, 150)
402+
@computed private get textMaxWidth(): number {
403+
return this.maxWidth - DEFAULT_CONNECTOR_LINE_WIDTH
404+
}
405+
406+
private makeLabelTextWrap(
407+
series: LineLabelSeries
408+
): TextWrap | TextWrapGroup {
409+
if (!series.formattedValue) {
410+
return new TextWrap({
411+
text: series.label,
412+
maxWidth: this.textMaxWidth,
413+
fontSize: this.fontSize,
414+
// focused labels are bold while non-focused labels are regular.
415+
// if we used the actual font-weights to compute the layout,
416+
// the layout would be jumpy since different font weights lead
417+
// to different text widths. that's why we always use bold labels
418+
// for comupting the layout.
419+
fontWeight: 700,
420+
})
421+
}
388422

423+
// text label fragment
424+
const textLabel = { text: series.label, fontWeight: 700 }
425+
426+
// value label fragment
427+
const newLine = series.placeFormattedValueInNewLine
428+
? "always"
429+
: "avoid-wrap"
430+
const valueLabel = {
431+
text: series.formattedValue,
432+
fontWeight: 400,
433+
newLine,
434+
}
435+
436+
return new TextWrapGroup({
437+
fragments: [textLabel, valueLabel],
438+
maxWidth: this.textMaxWidth,
439+
fontSize: this.fontSize,
440+
})
441+
}
442+
443+
private makeAnnotationTextWrap(
444+
series: LineLabelSeries
445+
): TextWrap | undefined {
446+
if (!series.annotation) return undefined
447+
const maxWidth = Math.min(this.textMaxWidth, 150)
448+
return new TextWrap({
449+
text: series.annotation,
450+
maxWidth,
451+
fontSize: this.fontSize * 0.9,
452+
lineHeight: 1,
453+
})
454+
}
455+
456+
@computed.struct get sizedLabels(): SizedSeries[] {
457+
const { fontWeight: globalFontWeight } = this
389458
return this.props.labelSeries.map((label) => {
390-
// if a formatted value is given, make the main label bold by default
391-
const fontWeight =
392-
this.fontWeight ?? (label.formattedValue ? 700 : undefined)
393-
394-
const mainLabel = { text: label.label, fontWeight }
395-
const valueLabel = label.formattedValue
396-
? {
397-
text: label.formattedValue,
398-
newLine: (label.placeFormattedValueInNewLine
399-
? "always"
400-
: "avoid-wrap") as "always" | "avoid-wrap",
401-
}
402-
: undefined
403-
const labelFragments = excludeUndefined([mainLabel, valueLabel])
404-
const textWrap = new TextWrapGroup({
405-
fragments: labelFragments,
406-
maxWidth: maxTextWidth,
407-
fontSize,
408-
})
409-
const annotationTextWrap = label.annotation
410-
? new TextWrap({
411-
text: label.annotation,
412-
maxWidth: maxAnnotationWidth,
413-
fontSize: fontSize * 0.9,
414-
lineHeight: 1,
415-
})
416-
: undefined
417-
418-
const annotationWidth = annotationTextWrap
419-
? annotationTextWrap.width
420-
: 0
459+
const textWrap = this.makeLabelTextWrap(label)
460+
const annotationTextWrap = this.makeAnnotationTextWrap(label)
461+
462+
const annotationWidth = annotationTextWrap?.width ?? 0
421463
const annotationHeight = annotationTextWrap
422464
? ANNOTATION_PADDING + annotationTextWrap.height
423465
: 0
424466

467+
// font weight priority:
468+
// series focus state > globally set font weight > default font weight
469+
const seriesFontWeight = label.focus?.active ? 700 : undefined
470+
const defaultFontWeight = label.formattedValue ? 700 : undefined
471+
const fontWeight =
472+
seriesFontWeight ?? globalFontWeight ?? defaultFontWeight
473+
425474
return {
426475
...label,
427476
textWrap,
428477
annotationTextWrap,
429478
width: Math.max(textWrap.width, annotationWidth),
430479
height: textWrap.height + annotationHeight,
480+
fontWeight,
431481
}
432482
})
433483
}

0 commit comments

Comments
 (0)