-
-
Notifications
You must be signed in to change notification settings - Fork 229
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
🔨 drop vertical color legend observer
- Loading branch information
1 parent
c549549
commit 7d2fd51
Showing
6 changed files
with
324 additions
and
302 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
117 changes: 117 additions & 0 deletions
117
packages/@ourworldindata/grapher/src/verticalColorLegend/VerticalColorLegend.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,117 @@ | ||
import { sum, max } from "@ourworldindata/utils" | ||
import { TextWrap } from "@ourworldindata/components" | ||
import { computed } from "mobx" | ||
import { | ||
GRAPHER_FONT_SCALE_11_2, | ||
BASE_FONT_SIZE, | ||
} from "../core/GrapherConstants" | ||
import { Color } from "@ourworldindata/types" | ||
|
||
export interface VerticalColorLegendProps { | ||
legendItems: LegendItem[] | ||
maxLegendWidth?: number | ||
fontSize?: number | ||
legendTitle?: string | ||
activeColors?: Color[] // inactive colors are grayed out | ||
focusColors?: Color[] // focused colors are bolded | ||
} | ||
|
||
export interface LegendItem { | ||
label?: string | ||
minText?: string | ||
maxText?: string | ||
color: Color | ||
} | ||
|
||
interface SizedLegendSeries { | ||
textWrap: TextWrap | ||
color: Color | ||
width: number | ||
height: number | ||
yOffset: number | ||
} | ||
|
||
export class VerticalColorLegend { | ||
rectPadding = 5 | ||
lineHeight = 5 | ||
|
||
props: VerticalColorLegendProps | ||
constructor(props: VerticalColorLegendProps) { | ||
this.props = props | ||
} | ||
|
||
@computed private get maxLegendWidth(): number { | ||
return this.props.maxLegendWidth ?? 100 | ||
} | ||
|
||
@computed private get fontSize(): number { | ||
return GRAPHER_FONT_SCALE_11_2 * (this.props.fontSize ?? BASE_FONT_SIZE) | ||
} | ||
|
||
@computed get rectSize(): number { | ||
return Math.round(this.fontSize / 1.4) | ||
} | ||
|
||
@computed get title(): TextWrap | undefined { | ||
if (!this.props.legendTitle) return undefined | ||
return new TextWrap({ | ||
maxWidth: this.maxLegendWidth, | ||
fontSize: this.fontSize, | ||
fontWeight: 700, | ||
lineHeight: 1, | ||
text: this.props.legendTitle, | ||
}) | ||
} | ||
|
||
@computed private get titleHeight(): number { | ||
if (!this.title) return 0 | ||
return this.title.height + 5 | ||
} | ||
|
||
@computed get series(): SizedLegendSeries[] { | ||
const { fontSize, rectSize, rectPadding, titleHeight, lineHeight } = | ||
this | ||
|
||
let runningYOffset = titleHeight | ||
return this.props.legendItems.map((series) => { | ||
let label = series.label | ||
// infer label for numeric bins | ||
if (!label && series.minText && series.maxText) { | ||
label = `${series.minText} – ${series.maxText}` | ||
} | ||
const textWrap = new TextWrap({ | ||
maxWidth: this.maxLegendWidth, | ||
fontSize, | ||
lineHeight: 1, | ||
text: label ?? "", | ||
}) | ||
const width = rectSize + rectPadding + textWrap.width | ||
const height = Math.max(textWrap.height, rectSize) | ||
const yOffset = runningYOffset | ||
|
||
runningYOffset += height + lineHeight | ||
|
||
return { | ||
textWrap, | ||
color: series.color, | ||
width, | ||
height, | ||
yOffset, | ||
} | ||
}) | ||
} | ||
|
||
@computed get width(): number { | ||
const widths = this.series.map((series) => series.width) | ||
if (this.title) widths.push(this.title.width) | ||
return max(widths) ?? 0 | ||
} | ||
|
||
@computed get height(): number { | ||
return ( | ||
this.titleHeight + | ||
sum(this.series.map((series) => series.height)) + | ||
this.lineHeight * this.series.length | ||
) | ||
} | ||
} |
Oops, something went wrong.