diff --git a/.gitignore b/.gitignore index 8de9cbdf9..87ca34f46 100644 --- a/.gitignore +++ b/.gitignore @@ -14,3 +14,4 @@ web/build web/node_modules web/coverage core +!/web/**/*.ts \ No newline at end of file diff --git a/web/src/components/Timeline/ScrollPermission.ts b/web/src/components/Timeline/ScrollPermission.ts new file mode 100644 index 000000000..c0fe084c9 --- /dev/null +++ b/web/src/components/Timeline/ScrollPermission.ts @@ -0,0 +1,4 @@ +export interface ScrollPermission { + allowed: boolean; + resetAfterSeeked: boolean; +} \ No newline at end of file diff --git a/web/src/components/Timeline/TimelineBlockView.tsx b/web/src/components/Timeline/TimelineBlockView.tsx index dea13f1a6..420266e52 100644 --- a/web/src/components/Timeline/TimelineBlockView.tsx +++ b/web/src/components/Timeline/TimelineBlockView.tsx @@ -1,6 +1,6 @@ import { h } from 'preact'; import { useCallback } from 'preact/hooks'; -import { getColorFromTimelineEvent } from '../../utils/Timeline/timelineEventUtils'; +import { getColorFromTimelineEvent } from '../../utils/tailwind/twTimelineEventUtil'; import { TimelineEventBlock } from './TimelineEventBlock'; interface TimelineBlockViewProps { @@ -14,7 +14,7 @@ export const TimelineBlockView = ({ block, onClick }: TimelineBlockViewProps) =>
{ + if (secondEvent.startTime < firstEvent.endTime && secondEvent.startTime > firstEvent.startTime) { + return true; + } + return false; +}; + +export const getTimelineEventBlocksFromTimelineEvents = (events: TimelineEvent[], xOffset: number): TimelineEventBlock[] => { + const firstEvent = events[0]; + const firstEventTime = longToDate(firstEvent.start_time); + return events + .map((e, index) => { + const startTime = longToDate(e.start_time); + const endTime = e.end_time ? longToDate(e.end_time) : new Date(); + const seconds = Math.round(Math.abs(endTime.getTime() - startTime.getTime()) / 1000); + const positionX = Math.round(Math.abs(startTime.getTime() - firstEventTime.getTime()) / 1000 + xOffset); + return { + ...e, + startTime, + endTime, + width: seconds, + positionX, + index, + } as TimelineEventBlock; + }) + .reduce((rowMap, current) => { + for (let i = 0; i < rowMap.length; i++) { + const row = rowMap[i] ?? []; + const lastItem = row[row.length - 1]; + if (lastItem) { + const isOverlap = checkEventForOverlap(lastItem, current); + if (isOverlap) { + continue; + } + } + rowMap[i] = [...row, current]; + return rowMap; + } + rowMap.push([current]); + return rowMap; + }, [] as TimelineEventBlock[][]) + .flatMap((rows, rowPosition) => { + rows.forEach((eventBlock) => { + const OFFSET_DISTANCE_IN_PIXELS = 10; + eventBlock.yOffset = OFFSET_DISTANCE_IN_PIXELS * rowPosition; + }); + return rows; + }) + .sort((a, b) => a.startTime.getTime() - b.startTime.getTime()); +} + +export const findLargestYOffsetInBlocks = (blocks: TimelineEventBlock[]): number => { + return blocks.reduce((largestYOffset, current) => { + if (current.yOffset > largestYOffset) { + return current.yOffset + } + return largestYOffset; + }, 0) +}; + +export const getTimelineWidthFromBlocks = (blocks: TimelineEventBlock[], offset: number): number => { + const firstBlock = blocks[0]; + if (firstBlock) { + const startTimeEpoch = firstBlock.startTime.getTime(); + const endTimeEpoch = Date.now(); + const timelineDurationLong = epochToLong(endTimeEpoch - startTimeEpoch); + return timelineDurationLong + offset * 2 + } +} diff --git a/web/src/utils/dateUtil.ts b/web/src/utils/dateUtil.ts new file mode 100644 index 000000000..51c9bcaa3 --- /dev/null +++ b/web/src/utils/dateUtil.ts @@ -0,0 +1,16 @@ +export const longToDate = (long: number): Date => new Date(long * 1000); +export const epochToLong = (date: number): number => date / 1000; +export const dateToLong = (date: Date): number => epochToLong(date.getTime()); + +const getDateTimeYesterday = (dateTime: Date): Date => { + const twentyFourHoursInMilliseconds = 24 * 60 * 60 * 1000; + return new Date(dateTime.getTime() - twentyFourHoursInMilliseconds); +} + +const getNowYesterday = (): Date => { + return getDateTimeYesterday(new Date()); +} + +export const getNowYesterdayInLong = (): number => { + return dateToLong(getNowYesterday()); +}; diff --git a/web/src/utils/objectUtils.ts b/web/src/utils/objectUtils.ts new file mode 100644 index 000000000..01aab7839 --- /dev/null +++ b/web/src/utils/objectUtils.ts @@ -0,0 +1 @@ +export const isNullOrUndefined = (object?: unknown): boolean => object === null || object === undefined; \ No newline at end of file diff --git a/web/src/utils/tailwind/twTimelineEventUtil.ts b/web/src/utils/tailwind/twTimelineEventUtil.ts new file mode 100644 index 000000000..c8bc6628b --- /dev/null +++ b/web/src/utils/tailwind/twTimelineEventUtil.ts @@ -0,0 +1,15 @@ +import { TimelineEvent } from "../../components/Timeline/TimelineEvent"; + +export const getColorFromTimelineEvent = (event: TimelineEvent) => { + const { label } = event; + if (label === 'car') { + return 'bg-red-400'; + } else if (label === 'person') { + return 'bg-blue-400'; + } else if (label === 'dog') { + return 'bg-green-400'; + } + + // unknown label + return 'bg-gray-400'; +}; \ No newline at end of file diff --git a/web/src/utils/windowUtils.ts b/web/src/utils/windowUtils.ts new file mode 100644 index 000000000..fc12b0096 --- /dev/null +++ b/web/src/utils/windowUtils.ts @@ -0,0 +1,3 @@ +export const convertRemToPixels = (rem: number): number => { + return rem * parseFloat(getComputedStyle(document.documentElement).fontSize); +} diff --git a/web/tailwind.config.js b/web/tailwind.config.js index e4ecad73c..774af9f06 100644 --- a/web/tailwind.config.js +++ b/web/tailwind.config.js @@ -1,5 +1,5 @@ module.exports = { - purge: ['./public/**/*.html', './src/**/*.jsx', './src/**/*.tsx'], + purge: ['./public/**/*.html', './src/**/*.{jsx,tsx}', './src/utils/tailwind/*.{jsx,tsx,js,ts}'], darkMode: 'class', theme: { extend: {