Skip to content

Commit

Permalink
🐛 (facets) show axes for no data charts
Browse files Browse the repository at this point in the history
  • Loading branch information
sophiamersmann committed Jun 26, 2024
1 parent dd1d28c commit 63d15cd
Show file tree
Hide file tree
Showing 9 changed files with 148 additions and 105 deletions.
13 changes: 7 additions & 6 deletions packages/@ourworldindata/grapher/src/axis/Axis.ts
Original file line number Diff line number Diff line change
Expand Up @@ -147,14 +147,15 @@ abstract class AbstractAxis {
updateDomainPreservingUserSettings(
domain: [number | undefined, number | undefined]
): this {
this.domain = [
const left =
domain[0] !== undefined
? Math.min(this.domain[0], domain[0])
: this.domain[0],
? min([this.domain[0], domain[0]])
: this.domain[0]
const right =
domain[1] !== undefined
? Math.max(this.domain[1], domain[1])
: this.domain[1],
]
? max([this.domain[1], domain[1]])
: this.domain[1]
this.domain = [left ?? 0, right ?? 0]
return this
}

Expand Down
1 change: 1 addition & 0 deletions packages/@ourworldindata/grapher/src/core/Grapher.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3221,6 +3221,7 @@ export class Grapher
this.canSelectMultipleEntities &&
(this.isLineChart ||
this.isStackedArea ||
this.isStackedBar ||
this.isDiscreteBar ||
this.isStackedDiscreteBar)
)
Expand Down
47 changes: 27 additions & 20 deletions packages/@ourworldindata/grapher/src/lineCharts/LineChart.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -757,20 +757,37 @@ export class LineChart
}

render(): React.ReactElement {
if (this.failMessage)
return (
<NoDataModal
manager={this.manager}
bounds={this.bounds}
message={this.failMessage}
/>
)

const { manager, tooltip, dualAxis, clipPath, activeXVerticalLine } =
this

const comparisonLines = manager.comparisonLines || []

const dualAxisComponent = (
<DualAxisComponent
dualAxis={dualAxis}
showTickMarks={true}
labelColor={manager.secondaryColorInStaticCharts}
lineWidth={
manager.isStaticAndSmall
? GRAPHER_AXIS_LINE_WIDTH_THICK
: GRAPHER_AXIS_LINE_WIDTH_DEFAULT
}
detailsMarker={manager.detailsMarkerInSvg}
/>
)

if (this.failMessage)
return (
<g className="LineChart">
{dualAxisComponent}
<NoDataModal
manager={this.manager}
bounds={dualAxis.innerBounds}
message={this.failMessage}
/>
</g>
)

// The tiny bit of extra space in the clippath is to ensure circles centered on the very edge are still fully visible
return (
<g
Expand All @@ -793,17 +810,7 @@ export class LineChart
{this.hasColorLegend && (
<HorizontalNumericColorLegend manager={this} />
)}
<DualAxisComponent
dualAxis={dualAxis}
showTickMarks={true}
labelColor={manager.secondaryColorInStaticCharts}
lineWidth={
manager.isStaticAndSmall
? GRAPHER_AXIS_LINE_WIDTH_THICK
: GRAPHER_AXIS_LINE_WIDTH_DEFAULT
}
detailsMarker={manager.detailsMarkerInSvg}
/>
{dualAxisComponent}
<g clipPath={clipPath.id}>
{comparisonLines.map((line, index) => (
<ComparisonLine
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -161,8 +161,6 @@ class Label extends React.Component<{
}

export interface LineLegendManager {
canAddData?: boolean
entityType?: string
labelSeries: LineLabelSeries[]
maxLineLegendWidth?: number
fontSize?: number
Expand Down
26 changes: 21 additions & 5 deletions packages/@ourworldindata/grapher/src/noDataModal/NoDataModal.scss
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,26 @@
justify-content: center;
height: 100%;

.action {
background-color: $controls-color;
border-radius: 2px;
padding: 8px 10px;
color: #fff;
.content {
width: fit-content;
background: rgba(#fff, 0.8);
margin: 12px auto;
padding: 4px 8px;
}

h4,
p {
margin: 0;
}

h4 {
color: $dark-text;
margin-bottom: 0.5em;
font-weight: 500;
}

p {
color: $light-text;
font-size: 0.9em;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ export const WithAddDataButtons = (): React.ReactElement => {
message="You have no data, but this is only a test"
manager={{
canChangeEntity: true,
canAddData: true,
canAddEntities: true,
isEntitySelectorModalOrDrawerOpen: false,
entityType: "Country",
}}
Expand Down
63 changes: 33 additions & 30 deletions packages/@ourworldindata/grapher/src/noDataModal/NoDataModal.tsx
Original file line number Diff line number Diff line change
@@ -1,15 +1,19 @@
import React from "react"
import { action, computed } from "mobx"
import { computed } from "mobx"
import { observer } from "mobx-react"
import a from "indefinite"
import { Bounds, DEFAULT_BOUNDS } from "@ourworldindata/utils"
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome/index.js"
import { faPlus, faRightLeft } from "@fortawesome/free-solid-svg-icons"
import {
DEFAULT_GRAPHER_ENTITY_TYPE,
DEFAULT_GRAPHER_ENTITY_TYPE_PLURAL,
} from "../core/GrapherConstants"

export interface NoDataModalManager {
canChangeEntity?: boolean
canAddData?: boolean
isEntitySelectorModalOrDrawerOpen?: boolean
canAddEntities?: boolean
entityType?: string
entityTypePlural?: string
fontSize?: number
}

@observer
Expand All @@ -18,45 +22,44 @@ export class NoDataModal extends React.Component<{
message?: string
manager: NoDataModalManager
}> {
@action.bound private onDataSelect(): void {
this.props.manager.isEntitySelectorModalOrDrawerOpen = true
}

@computed private get bounds(): Bounds {
return this.props.bounds ?? DEFAULT_BOUNDS
}

@computed private get manager(): NoDataModalManager {
return this.props.manager
}

@computed private get fontSize(): number {
return this.manager.fontSize ?? 16
}

render(): React.ReactElement {
const { message, manager } = this.props
const entityType = manager.entityType
const { bounds } = this
const { message } = this.props
const {
entityType = DEFAULT_GRAPHER_ENTITY_TYPE,
entityTypePlural = DEFAULT_GRAPHER_ENTITY_TYPE_PLURAL,
canAddEntities,
canChangeEntity,
} = this.manager
return (
<foreignObject
x={bounds.left}
y={bounds.top}
width={bounds.width}
height={bounds.height}
>
<div className="NoData">
<p className="message">{message || "No available data"}</p>
<div className="actions">
{manager.canAddData && (
<button
className="action"
onClick={this.onDataSelect}
>
<FontAwesomeIcon icon={faPlus} /> Add{" "}
{entityType}
</button>
<div className="NoData" style={{ fontSize: this.fontSize }}>
<div className="content">
<h4>{message || "No available data"}</h4>
{canAddEntities && (
<p>
Try adding {entityTypePlural} to display data.
</p>
)}
{manager.canChangeEntity && (
<button
className="action"
onClick={this.onDataSelect}
>
<FontAwesomeIcon icon={faRightLeft} /> Change{" "}
{entityType}
</button>
{canChangeEntity && (
<p>Try choosing {a(entityType)} to display data.</p>
)}
</div>
</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -571,20 +571,36 @@ export class StackedAreaChart
}

render(): React.ReactElement {
if (this.failMessage)
return (
<NoDataModal
manager={this.manager}
bounds={this.props.bounds}
message={this.failMessage}
/>
)

const { manager, bounds, dualAxis, renderUid, series } = this
const { target } = this.tooltipState

const showLegend = this.manager.showLegend

const dualAxisComponent = (
<DualAxisComponent
dualAxis={dualAxis}
showTickMarks={true}
labelColor={manager.secondaryColorInStaticCharts}
lineWidth={
manager.isStaticAndSmall
? GRAPHER_AXIS_LINE_WIDTH_THICK
: GRAPHER_AXIS_LINE_WIDTH_DEFAULT
}
detailsMarker={manager.detailsMarkerInSvg}
/>
)

if (this.failMessage)
return (
<g className="StackedArea">
{dualAxisComponent}
<NoDataModal
manager={this.manager}
bounds={dualAxis.bounds}
message={this.failMessage}
/>
</g>
)

const clipPath = makeClipPath(renderUid, {
...bounds,
height: bounds.height * 2,
Expand All @@ -609,17 +625,7 @@ export class StackedAreaChart
whole charting area, including the axis, the entity labels, and the whitespace next to them.
We need these to be able to show the tooltip for the first/last year even if the mouse is outside the charting area. */}
</rect>
<DualAxisComponent
dualAxis={dualAxis}
showTickMarks={true}
labelColor={manager.secondaryColorInStaticCharts}
lineWidth={
manager.isStaticAndSmall
? GRAPHER_AXIS_LINE_WIDTH_THICK
: GRAPHER_AXIS_LINE_WIDTH_DEFAULT
}
detailsMarker={manager.detailsMarkerInSvg}
/>
{dualAxisComponent}
<g clipPath={clipPath.id}>
{showLegend && <LineLegend manager={this} />}
<Areas
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -426,15 +426,6 @@ export class StackedBarChart
}

render(): React.ReactElement {
if (this.failMessage)
return (
<NoDataModal
manager={this.manager}
bounds={this.bounds}
message={this.failMessage}
/>
)

const {
manager,
dualAxis,
Expand All @@ -447,6 +438,36 @@ export class StackedBarChart
const { series } = this
const { innerBounds, verticalAxis, horizontalAxis } = dualAxis

const dualAxisComponent = (
<DualAxisComponent
dualAxis={dualAxis}
showTickMarks={true}
labelColor={manager.secondaryColorInStaticCharts}
lineWidth={
manager.isStaticAndSmall
? GRAPHER_AXIS_LINE_WIDTH_THICK
: GRAPHER_AXIS_LINE_WIDTH_DEFAULT
}
detailsMarker={manager.detailsMarkerInSvg}
/>
)

if (this.failMessage)
return (
<g
className="StackedBarChart"
width={bounds.width}
height={bounds.height}
>
{dualAxisComponent}
<NoDataModal
manager={this.manager}
bounds={dualAxis.innerBounds}
message={this.failMessage}
/>
</g>
)

const clipPath = makeClipPath(renderUid, innerBounds)

const legend = this.showHorizontalLegend ? (
Expand All @@ -473,17 +494,7 @@ export class StackedBarChart
fill="rgba(255,255,255,0)"
/>

<DualAxisComponent
dualAxis={dualAxis}
showTickMarks={true}
labelColor={manager.secondaryColorInStaticCharts}
lineWidth={
manager.isStaticAndSmall
? GRAPHER_AXIS_LINE_WIDTH_THICK
: GRAPHER_AXIS_LINE_WIDTH_DEFAULT
}
detailsMarker={manager.detailsMarkerInSvg}
/>
{dualAxisComponent}

<g clipPath={clipPath.id}>
{series.map((series, index) => {
Expand Down

0 comments on commit 63d15cd

Please sign in to comment.