Skip to content
This repository has been archived by the owner on Mar 3, 2025. It is now read-only.

Commit

Permalink
Leg content in itinerary headers
Browse files Browse the repository at this point in the history
  • Loading branch information
testower committed Sep 28, 2023
1 parent 1c24cec commit dfa1c20
Show file tree
Hide file tree
Showing 6 changed files with 172 additions and 8 deletions.
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { TripPattern } from '../../gql/graphql.ts';
import { TIME_WIDTH, useHeaderContentStyleCalculations } from './useHeaderContentStyleCalculations.ts';
import { TIME_BOX_WIDTH, useHeaderContentStyleCalculations } from './useHeaderContentStyleCalculations.ts';
import { ItineraryHeaderLegContent } from './ItineraryHeaderLegContent.tsx';

export function ItineraryHeaderContent({
tripPattern,
Expand All @@ -14,7 +15,7 @@ export function ItineraryHeaderContent({
earliestStartTime: string | null;
latestEndTime: string | null;
}) {
const { widthPx, leftPx } = useHeaderContentStyleCalculations(
const { maxSpan, pxSpan, startPx, widthPx, leftPx } = useHeaderContentStyleCalculations(
tripPattern,
containerWidth,
earliestStartTime,
Expand All @@ -37,9 +38,15 @@ export function ItineraryHeaderContent({
<div
style={{
position: 'absolute',
left: `${leftPx - TIME_WIDTH}px`,
left: `${leftPx - TIME_BOX_WIDTH}px`,
background: 'black',
color: 'white',
fontSize: '12px',
width: '38px',
height: '15px',
textAlign: 'center',
top: 2,
padding: 1,
}}
>
{new Date(tripPattern.expectedStartTime).toLocaleTimeString('en-US', {
Expand All @@ -48,12 +55,28 @@ export function ItineraryHeaderContent({
})}
</div>

{tripPattern.legs.map((leg) => (
<ItineraryHeaderLegContent
leg={leg}
earliestStartTime={earliestStartTime}
startPx={startPx}
maxSpan={maxSpan}
pxSpan={pxSpan}
/>
))}

<div
style={{
position: 'absolute',
left: `${leftPx + widthPx + 2}px`,
background: 'black',
color: 'white',
fontSize: '12px',
width: '38px',
height: '15px',
textAlign: 'center',
top: 2,
padding: 1,
}}
>
{new Date(tripPattern.expectedEndTime).toLocaleTimeString('en-US', {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
import { Leg } from '../../gql/graphql.ts';
import { useMemo } from 'react';
import { getColorForMode } from '../../util/getColorForMode.ts';
import { isTransitMode } from '../../util/isTransitMode.ts';
import { generateTextColor } from '../../util/generateTextColor.ts';

export function ItineraryHeaderLegContent({
leg,
earliestStartTime,
maxSpan,
startPx,
pxSpan,
}: {
leg: Leg;
earliestStartTime: string | null;
maxSpan: number;
startPx: number;
pxSpan: number;
}) {
const startPct = useMemo(
() => (new Date(leg.expectedStartTime).getTime() - new Date(earliestStartTime!).getTime()) / maxSpan,
[leg.expectedStartTime, earliestStartTime, maxSpan],
);

const widthPx = useMemo(
() =>
(pxSpan * (new Date(leg.expectedEndTime).getTime() - new Date(leg.expectedStartTime).getTime())) / maxSpan - 1,
[pxSpan, leg, maxSpan],
);

const leftPx = startPx + startPct * pxSpan + 1;

const showPublicCode =
widthPx > 40 && isTransitMode(leg.mode) && leg.line?.publicCode && leg.line.publicCode.length <= 6;

const modeColor = getColorForMode(leg.mode);
const legTextColor = useMemo(() => generateTextColor(modeColor), [modeColor]);

return (
<div
style={{
position: 'absolute',
width: `${widthPx}px`,
height: '22px',
left: leftPx,
color: legTextColor,
background: modeColor,
fontWeight: 'bold',
textShadow: 'none',
marginTop: '-1px',
paddingTop: '3px',
textAlign: 'center',
overflow: 'hidden',
}}
>
<div
style={{
background: legTextColor,
maskImage: `url(/img/mode/${leg.mode.toLowerCase()}.png)`,
maskRepeat: 'no-repeat',
WebkitMaskImage: `url(/img/mode/${leg.mode.toLowerCase()}.png)`,
WebkitMaskRepeat: 'no-repeat',
width: '17px',
height: '17px',
display: 'inline-block',
}}
></div>
{showPublicCode && (
<span style={{ verticalAlign: 'top', fontSize: '14px', paddingLeft: '2px' }}>{leg.line?.publicCode}</span>
)}
</div>
);
}
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
import { useMemo } from 'react';
import { TripPattern } from '../../gql/graphql.ts';

const CONTAINER_WIDTH_PADDING = 90;
const CONTAINER_WIDTH_PADDING = 70;
const START_PX_PADDING = 20;

export const TIME_WIDTH = 40;
// Width of time box
export const TIME_BOX_WIDTH = 40;

export function useHeaderContentStyleCalculations(
tripPattern: TripPattern,
Expand All @@ -27,13 +28,16 @@ export function useHeaderContentStyleCalculations(
[tripPattern.expectedStartTime, tripPattern.expectedEndTime],
);

const startPx = START_PX_PADDING + TIME_WIDTH;
const endPx = containerWidth - CONTAINER_WIDTH_PADDING - TIME_WIDTH;
const startPx = START_PX_PADDING + TIME_BOX_WIDTH;
const endPx = containerWidth - CONTAINER_WIDTH_PADDING - TIME_BOX_WIDTH;
const pxSpan = endPx - startPx;
const leftPx = startPx + startPct * pxSpan;
const widthPx = pxSpan * (itinSpan / maxSpan);

return {
maxSpan,
startPx,
pxSpan,
widthPx,
leftPx,
};
Expand Down
8 changes: 7 additions & 1 deletion client-next/src/hooks/useTripQuery.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,13 @@ const query = graphql(`
legs {
id
mode
aimedStartTime
aimedEndTime
expectedEndTime
expectedStartTime
line {
publicCode
}
pointsOnLink {
points
}
Expand Down
40 changes: 40 additions & 0 deletions client-next/src/util/generateTextColor.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
/**
* textColor can be black or white. White for dark colors and black for light colors.
* Calculated based on luminance formula:
* sqrt( 0.299*Red^2 + 0.587*Green^2 + 0.114*Blue^2 )
*/
export function generateTextColor(hexColor: string) {
const color = decodeColor(hexColor);

//Calculates luminance based on https://stackoverflow.com/questions/596216/formula-to-determine-brightness-of-rgb-color
const newRed = 0.299 * Math.pow(color[0] / 255.0, 2.0);
const newGreen = 0.587 * Math.pow(color[1] / 255.0, 2.0);
const newBlue = 0.114 * Math.pow(color[2] / 255.0, 2.0);
const luminance = Math.sqrt(newRed + newGreen + newBlue);

if (luminance > 0.66) {
return '#000';
} else {
return '#fff';
}
}

function decodeColor(hex: string): number[] {
return hex2rgb(hex);
}

function hex2rgb(hex: string) {
if (hex.length === 4) {
return fullHex(hex);
}

return [parseInt(hex.slice(1, 3), 16), parseInt(hex.slice(3, 5), 16), parseInt(hex.slice(5, 7), 16)];
}

function fullHex(hex: string) {
let r = hex.slice(1, 2);
let g = hex.slice(2, 3);
let b = hex.slice(3, 4);

return [parseInt(r + r, 16), parseInt(g + g, 16), parseInt(b + b, 16)];
}
18 changes: 18 additions & 0 deletions client-next/src/util/isTransitMode.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { Mode } from '../gql/graphql.ts';

export function isTransitMode(mode: Mode) {
return (
mode === Mode.Rail ||
mode === Mode.Coach ||
mode === Mode.Metro ||
mode === Mode.Bus ||
mode === Mode.Tram ||
mode === Mode.Water ||
mode === Mode.Air ||
mode === Mode.Cableway ||
mode === Mode.Funicular ||
mode === Mode.Trolleybus ||
mode === Mode.Monorail ||
mode === Mode.Taxi
);
}

0 comments on commit dfa1c20

Please sign in to comment.