Skip to content

Commit

Permalink
✨ (discrete bar) move legend to the top on mobile
Browse files Browse the repository at this point in the history
  • Loading branch information
sophiamersmann committed May 22, 2024
1 parent 4ac4b65 commit 72de730
Show file tree
Hide file tree
Showing 5 changed files with 85 additions and 18 deletions.
1 change: 1 addition & 0 deletions packages/@ourworldindata/grapher/src/chart/ChartManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,7 @@ export interface ChartManager {
missingDataStrategy?: MissingDataStrategy

isNarrow?: boolean
isSemiNarrow?: boolean
isStaticAndSmall?: boolean
secondaryColorInStaticCharts?: string

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,6 @@ import { CategoricalBin, ColorScaleBin } from "../color/ColorScaleBin"

export interface SlopeChartManager extends ChartManager {
isModalOpen?: boolean
isSemiNarrow?: boolean
}

const LABEL_SLOPE_PADDING = 8
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,7 @@ export class AbstractStackedChart
@computed get manager(): ChartManager {
return this.props.manager
}

@computed get bounds(): Bounds {
return this.props.bounds ?? DEFAULT_BOUNDS
}
Expand All @@ -143,7 +144,11 @@ export class AbstractStackedChart
return this.manager.detailsOrderedByReference ?? []
}

protected get paddingForLegend(): number {
protected get paddingForLegendRight(): number {
return 0
}

protected get paddingForLegendTop(): number {
return 0
}

Expand Down Expand Up @@ -197,11 +202,13 @@ export class AbstractStackedChart
bounds,
horizontalAxisPart,
verticalAxisPart,
paddingForLegend,
paddingForLegendRight,
paddingForLegendTop,
} = this
return new DualAxis({
bounds: bounds
.padRight(paddingForLegend)
.padTop(paddingForLegendTop)
.padRight(paddingForLegendRight)
// top padding leaves room for tick labels
.padTop(6)
// bottom padding avoids axis labels to be cut off at some resolutions
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -305,7 +305,7 @@ export class StackedAreaChart

@observable hoverSeriesName?: SeriesName

@computed protected get paddingForLegend(): number {
@computed protected get paddingForLegendRight(): number {
const { legendDimensions } = this
return legendDimensions ? legendDimensions.width : 20
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,11 +38,17 @@ import {
} from "./AbstractStackedChart"
import { StackedPoint, StackedSeries } from "./StackedConstants"
import { VerticalAxis } from "../axis/Axis"
import { ColorSchemeName, VerticalAlign } from "@ourworldindata/types"
import {
ColorSchemeName,
HorizontalAlign,
VerticalAlign,
} from "@ourworldindata/types"
import { stackSeries, withMissingValuesAsZeroes } from "./StackedUtils"
import { makeClipPath } from "../chart/ChartUtils"
import { ColorScaleConfigDefaults } from "../color/ColorScaleConfig"
import { ColumnTypeMap } from "@ourworldindata/core-table"
import { HorizontalCategoricalColorLegend } from "../horizontalColorLegend/HorizontalColorLegends"
import { CategoricalBin, ColorScaleBin } from "../color/ColorScaleBin"

interface StackedBarSegmentProps extends React.SVGAttributes<SVGGElement> {
bar: StackedPoint<Time>
Expand Down Expand Up @@ -158,8 +164,22 @@ export class StackedBarChart
)
}

@computed protected get paddingForLegend(): number {
return this.sidebarWidth + 20
@computed private get showHorizontalLegend(): boolean {
return !!(this.manager.isSemiNarrow || this.manager.isStaticAndSmall)
}

@computed get legendAlign(): HorizontalAlign {
return HorizontalAlign.left
}

@computed protected get paddingForLegendRight(): number {
return this.showHorizontalLegend ? 0 : this.sidebarWidth + 20
}

@computed protected get paddingForLegendTop(): number {
return this.showHorizontalLegend
? this.horizontalColorLegend.height + 8
: 0
}

@computed get shouldRunLinearInterpolation(): boolean {
Expand Down Expand Up @@ -206,7 +226,9 @@ export class StackedBarChart
)
}

@computed get legendItems(): LegendItem[] {
// used by <VerticalColorLegend />
@computed get legendItems(): (LegendItem &
Required<Pick<LegendItem, "label">>)[] {
return this.series
.map((series) => {
return {
Expand All @@ -217,29 +239,61 @@ export class StackedBarChart
.reverse() // Vertical legend orders things in the opposite direction we want
}

// used by <HorizontalCategoricalColorLegend />
@computed get categoricalLegendData(): CategoricalBin[] {
return this.legendItems.map(
(legendItem, index) =>
new CategoricalBin({
index,
value: legendItem.label,
label: legendItem.label,
color: legendItem.color,
})
)
}

@computed get legendWidth(): number {
return this.showHorizontalLegend
? this.bounds.width
: this.verticalColorLegend.width
}

@computed get maxLegendWidth(): number {
return this.sidebarMaxWidth
return this.showHorizontalLegend
? this.bounds.width
: this.sidebarMaxWidth
}

@computed get sidebarMaxWidth(): number {
return this.bounds.width / 5
}

@computed get sidebarMinWidth(): number {
return 100
}

@computed get sidebarWidth(): number {
if (!this.manager.showLegend) return 0
const { sidebarMinWidth, sidebarMaxWidth, legendDimensions } = this
const {
sidebarMinWidth,
sidebarMaxWidth,
verticalColorLegend: legendDimensions,
} = this
return Math.max(
Math.min(legendDimensions.width, sidebarMaxWidth),
sidebarMinWidth
)
}

@computed private get legendDimensions(): VerticalColorLegend {
@computed private get verticalColorLegend(): VerticalColorLegend {
return new VerticalColorLegend({ manager: this })
}

@computed
private get horizontalColorLegend(): HorizontalCategoricalColorLegend {
return new HorizontalCategoricalColorLegend({ manager: this })
}

@computed get tooltip(): JSX.Element | undefined {
const {
tooltipState: { target, position, fading },
Expand Down Expand Up @@ -365,8 +419,8 @@ export class StackedBarChart
return tickPlacements.filter((t) => !t.isHidden)
}

@action.bound onLegendMouseOver(color: string): void {
this.hoverColor = color
@action.bound onLegendMouseOver(color: string | ColorScaleBin): void {
if (typeof color === "string") this.hoverColor = color
}

@action.bound onLegendMouseLeave(): void {
Expand Down Expand Up @@ -429,6 +483,12 @@ export class StackedBarChart
? GRAPHER_AXIS_LINE_WIDTH_THICK
: GRAPHER_AXIS_LINE_WIDTH_DEFAULT

const legend = this.showHorizontalLegend ? (
<HorizontalCategoricalColorLegend manager={this} />
) : (
<VerticalColorLegend manager={this} />
)

return (
<g
className="StackedBarChart"
Expand Down Expand Up @@ -537,9 +597,7 @@ export class StackedBarChart
})}
</g>

{this.manager.showLegend && (
<VerticalColorLegend manager={this} />
)}
{this.manager.showLegend && legend}
{tooltip}
</g>
)
Expand All @@ -550,7 +608,9 @@ export class StackedBarChart
}

@computed get legendX(): number {
return this.bounds.right - this.sidebarWidth
return this.showHorizontalLegend
? this.bounds.left
: this.bounds.right - this.sidebarWidth
}

@computed private get xValues(): number[] {
Expand Down

0 comments on commit 72de730

Please sign in to comment.