Skip to content

Commit

Permalink
🚧 make interaction state into record
Browse files Browse the repository at this point in the history
  • Loading branch information
sophiamersmann committed Dec 11, 2024
1 parent d151f5c commit 42513be
Show file tree
Hide file tree
Showing 8 changed files with 38 additions and 65 deletions.
12 changes: 3 additions & 9 deletions packages/@ourworldindata/grapher/src/chart/ChartUtils.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -197,15 +197,9 @@ export function findValidChartTypeCombination(
export function byInteractionState(series: {
hover: InteractionState
}): number {
// background series first,
// then series in their default state,
// then active series
switch (series.hover) {
case InteractionState.background:
return 1
case InteractionState.foreground:
return 2
}
if (series.hover.background) return 1
if (series.hover.active) return 3
return 2
}

export function findSeriesNamesContainedInBin(
Expand Down
47 changes: 21 additions & 26 deletions packages/@ourworldindata/grapher/src/lineCharts/LineChart.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,6 @@ import {
ColorScaleConfigInterface,
ColorSchemeName,
VerticalAlign,
InteractionState,
} from "@ourworldindata/types"
import {
GRAPHER_AXIS_LINE_WIDTH_THICK,
Expand Down Expand Up @@ -1283,7 +1282,7 @@ class Lines extends React.Component<LinesProps> {
if (this.props.hidePoints) return false
const totalPoints = sum(
this.props.series
.filter((s) => s.hover !== InteractionState.background)
.filter((series) => this.seriesHasMarkers(series))
.map((series) => series.placedPoints.length)
)
return totalPoints < 500
Expand Down Expand Up @@ -1314,24 +1313,17 @@ class Lines extends React.Component<LinesProps> {
}

private seriesHasMarkers(series: RenderLineChartSeries): boolean {
// Don't show markers for lines in the background
if (series.hover === InteractionState.background) return false

// If the series only contains one point, then we will always want to
// show a marker/circle because we can't draw a line.
return (
(this.hasMarkers || series.placedPoints.length === 1) &&
!series.isProjection
)
return !series.hover.background
}

renderLine(series: RenderLineChartSeries): React.ReactElement {
const { hover } = series

const color = series.placedPoints[0]?.color ?? DEFAULT_LINE_COLOR
const strokeDasharray = series.isProjection ? "2,3" : undefined

const nonHovered = series.hover === InteractionState.background
const strokeWidth = nonHovered ? 1 : this.strokeWidth
const strokeOpacity = nonHovered ? 0.3 : 1
const strokeWidth = hover.background ? 1 : this.strokeWidth
const strokeOpacity = hover.background ? 0.3 : 1

const outline = this.renderPathForSeries(series, {
id: makeIdForHumanConsumption("outline", series.seriesName),
Expand Down Expand Up @@ -1374,11 +1366,17 @@ class Lines extends React.Component<LinesProps> {
renderLineMarkers(
series: RenderLineChartSeries
): React.ReactElement | void {
if (!this.seriesHasMarkers(series)) return
// If the series only contains one point, then we will always want to
// show a marker/circle because we can't draw a line.
const forceMarkers = series.placedPoints.length === 1

// check if we should hide markers on the chart and series level
const hideMarkers = !this.hasMarkers || !this.seriesHasMarkers(series)

if (hideMarkers && !forceMarkers) return

const { horizontalAxis } = this.props.dualAxis
const nonHovered = series.hover === InteractionState.background
const opacity = nonHovered ? 0.3 : 1
const opacity = series.hover.background ? 0.3 : 1

return (
<g
Expand Down Expand Up @@ -1414,15 +1412,12 @@ class Lines extends React.Component<LinesProps> {
renderLines(): React.ReactElement {
return (
<>
{this.props.series.map((series) => {
const showMarkers = this.seriesHasMarkers(series)
return (
<React.Fragment key={series.seriesName}>
{this.renderLine(series)}
{showMarkers && this.renderLineMarkers(series)}
</React.Fragment>
)
})}
{this.props.series.map((series) => (
<React.Fragment key={series.seriesName}>
{this.renderLine(series)}
{this.renderLineMarkers(series)}
</React.Fragment>
))}
</>
)
}
Expand Down
19 changes: 2 additions & 17 deletions packages/@ourworldindata/grapher/src/lineLegend/LineLegend.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,7 @@ class LineLabels extends React.Component<{
}

private textOpacityForSeries(series: PlacedSeries): number {
return series.hover === InteractionState.background ? 0.6 : 1
return series.hover?.background ? 0.6 : 1
}

@computed private get markers(): {
Expand Down Expand Up @@ -225,10 +225,7 @@ class LineLabels extends React.Component<{
const step = (x2 - x1) / (totalLevels + 1)
const markerXMid = x1 + step + level * step
const d = `M${x1},${leftCenterY} H${markerXMid} V${rightCenterY} H${x2}`
const lineColor =
series.hover === InteractionState.background
? "#eee"
: "#999"
const lineColor = series.hover?.background ? "#eee" : "#999"

return (
<path
Expand Down Expand Up @@ -740,18 +737,6 @@ export class LineLegend extends React.Component<LineLegendProps> {
return this.partialInitialSeries.map((series) => series.seriesName)
}

@computed private get backgroundSeries(): PlacedSeries[] {
return this.placedSeries.filter(
(series) => series.hover === InteractionState.background
)
}

@computed private get focusedSeries(): PlacedSeries[] {
return this.placedSeries.filter(
(series) => series.hover !== InteractionState.background
)
}

// Does this placement need line markers or is the position of the labels already clear?
@computed private get needsLines(): boolean {
return this.placedSeries.some((series) => series.totalLevels > 1)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,9 +60,10 @@ export class InteractionArray {
* isn't currently interacted with.
*/
state(seriesName: SeriesName): InteractionState {
return this.isInForeground(seriesName)
? InteractionState.foreground
: InteractionState.background
return {
active: this.isActive(seriesName),
background: this.isInBackground(seriesName),
}
}

@action.bound private _activate(seriesName: SeriesName): this {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,6 @@ import {
EntityName,
VerticalAlign,
FacetStrategy,
InteractionState,
} from "@ourworldindata/types"
import { ChartInterface } from "../chart/ChartInterface"
import { ChartManager } from "../chart/ChartManager"
Expand Down Expand Up @@ -1285,7 +1284,7 @@ function Slope({
}: SlopeProps) {
const { seriesName, startPoint, endPoint } = series

const isInBackground = series.hover === InteractionState.background
const isInBackground = series.hover.background
const showOutline = !isInBackground
const opacity = isInBackground ? 0.3 : 1

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -297,10 +297,9 @@ export class StackedAreaChart extends AbstractStackedChart {
private hoverStateForSeries(
series: StackedSeries<number>
): InteractionState {
if (!this.focusedSeriesName) return InteractionState.foreground
return this.focusedSeriesName === series.seriesName
? InteractionState.foreground
: InteractionState.background
const active = this.focusedSeriesName === series.seriesName
const background = !!this.focusedSeriesName && !active
return { active, background }
}

@computed get lineLegendSeries(): LineLabelSeries[] {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -95,9 +95,9 @@ export enum DimensionProperty {
table = "table",
}

export enum InteractionState {
foreground = "foreground", // series is either actively hovered/focused or the chart is not currently being interacted with
background = "background", // another series is actively hovered/focused
export interface InteractionState {
active: boolean // actively hovered or focused
background: boolean // another series is actively hovered or focused
}

// see CoreTableConstants.ts
Expand Down
2 changes: 1 addition & 1 deletion packages/@ourworldindata/types/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,7 @@ export {
GrapherWindowType,
AxisMinMaxValueStr,
GrapherTooltipAnchor,
InteractionState,
type InteractionState,
} from "./grapherTypes/GrapherTypes.js"

export {
Expand Down

0 comments on commit 42513be

Please sign in to comment.