diff --git a/ui-charts/src/manchette/hooks/useManchetteWithSpaceTimeChart.tsx b/ui-charts/src/manchette/hooks/useManchetteWithSpaceTimeChart.tsx index 7679aae81..9589f81c8 100644 --- a/ui-charts/src/manchette/hooks/useManchetteWithSpaceTimeChart.tsx +++ b/ui-charts/src/manchette/hooks/useManchetteWithSpaceTimeChart.tsx @@ -2,7 +2,11 @@ import React, { type ReactNode, useCallback, useEffect, useMemo, useState } from import { sortBy, clamp } from 'lodash'; -import { type SpaceScale, type SpaceTimeChartProps } from '../../spaceTimeChart'; +import { + getCrispLineCoordinate, + type SpaceScale, + type SpaceTimeChartProps, +} from '../../spaceTimeChart'; import { getSpaceToPixel, spaceScalesToBinaryTree } from '../../spaceTimeChart/utils/scales'; import type { ManchetteProps } from '../components/Manchette'; import { @@ -462,6 +466,11 @@ const useManchetteWithSpaceTimeChart = ({ // Sort all contents by position: const allSortedContents = sortBy(allContents, 'position'); + // In practice, waypoint lines are 0.5px wide only when devicePixelRatio is at least 2 (as it's + // implemented at the end of waypoint.css). But to get the proper alignment, we always consider + // it to be 0.5px wide here, because they always have this thickness SpaceTimeChart side: + const waypointLinesThickness = 0.5; + // Iterate over all contents, to set each split section's style, and correct waypoints styles // accordingly: const finalContents: (InteractiveWaypoint | ReactNode)[] = []; @@ -472,7 +481,7 @@ const useManchetteWithSpaceTimeChart = ({ ...content.waypoint, styles: { position: 'absolute', - top: `${getSpacePixel(content.position)}px`, + top: `${getCrispLineCoordinate(getSpacePixel(content.position), waypointLinesThickness)}px`, height: `${BASE_WAYPOINT_HEIGHT}px`, }, }); diff --git a/ui-charts/src/manchette/styles/waypoint.css b/ui-charts/src/manchette/styles/waypoint.css index 8c9dbafe6..cddb3dabb 100644 --- a/ui-charts/src/manchette/styles/waypoint.css +++ b/ui-charts/src/manchette/styles/waypoint.css @@ -5,6 +5,7 @@ padding-block: 3px 5px; width: 315px; position: relative; + &-separator { position: relative; opacity: 0.6; @@ -19,7 +20,6 @@ bottom: 11px; left: 0; width: 100%; - height: 0.5px; @apply bg-grey-40; } } @@ -92,8 +92,22 @@ bottom: 16px; right: -1.625rem; width: 1.625rem; - height: 0.5px; opacity: 0.6; @apply bg-grey-40; } + + /** + * Handle lines thickness, so that they are 0.5px wide only when DPR is at least 2 (since Firefox, particularly, + * doesn't render subpixel wide lines): + */ + + &-separator::after, + &::after { + height: 0.5px; + margin-bottom: -0.25px; + + @media (max-resolution: 2x) { + height: 1px; + } + } } diff --git a/ui-charts/src/spaceTimeChart/index.ts b/ui-charts/src/spaceTimeChart/index.ts index da134ef09..3cd548884 100644 --- a/ui-charts/src/spaceTimeChart/index.ts +++ b/ui-charts/src/spaceTimeChart/index.ts @@ -33,3 +33,4 @@ export type { export { isPathOnScreen } from './utils/geometry'; export { getSpaceAtTime } from './utils/scales'; +export { getCrispLineCoordinate } from './utils/canvas';