Skip to content

Commit

Permalink
[Timeline]: made TimelineGrid customisable.
Browse files Browse the repository at this point in the history
  • Loading branch information
Kuznietsov committed Jul 10, 2024
1 parent 9731a00 commit 25ad078
Show file tree
Hide file tree
Showing 6 changed files with 205 additions and 112 deletions.
2 changes: 1 addition & 1 deletion app/src/demo/tables/editableTable/TimelineHeader.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ export function TimelineHeader({ timelineController }: TimelineHeaderProps) {
useResizeObserver({
onResize: onResize,
observables: [document.body, timelineRef.current],
delay: 100,
delay: 150,
});

return (
Expand Down
2 changes: 1 addition & 1 deletion uui-timeline/index.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
export * from './src/Canvas';
export * from './src/TimelineController';
export * from './src/TimelineContext';
export * from './src/draw';
export * from './src/TimelineGrid';
export * from './src/TimelineNav';
export * from './src/TimelineScale';
Expand Down
9 changes: 0 additions & 9 deletions uui-timeline/src/TimelineContext.ts

This file was deleted.

160 changes: 59 additions & 101 deletions uui-timeline/src/TimelineGrid.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,132 +2,90 @@ import React from 'react';
import { TimelineTransform } from './TimelineTransform';
import { msPerDay } from './helpers';
import { Canvas, CanvasProps } from './Canvas';
import { CanvasDrawLineProps, CanvasDrawTimelineElementProps, timelineGrid } from './draw';

export interface TimelineGridProps extends CanvasProps {
drawLine?: (props: CanvasDrawLineProps) => void;
drawMinutes?: (props: CanvasDrawTimelineElementProps) => void;
drawHours?: (props: CanvasDrawTimelineElementProps) => void;
drawDays?: (props: CanvasDrawTimelineElementProps) => void;
drawQuoterHours?: (props: CanvasDrawTimelineElementProps) => void;
drawHolidays?: (props: CanvasDrawTimelineElementProps) => void;
drawWeeks?: (props: CanvasDrawTimelineElementProps) => void;
drawMonths?: (props: CanvasDrawTimelineElementProps) => void;
drawYears?: (props: CanvasDrawTimelineElementProps) => void;
drawToday?: (props: CanvasDrawTimelineElementProps) => void;
}

export interface TimelineGridProps extends CanvasProps {}

export function TimelineGrid({ timelineController, ...restProps }: TimelineGridProps) {
export function TimelineGrid({
timelineController,
drawLine,
drawMinutes,
drawQuoterHours,
drawHours,
drawDays,
drawHolidays,
drawWeeks,
drawMonths,
drawYears,
drawToday,
...restProps
}: TimelineGridProps) {
const canvasHeight = restProps.canvasHeight ?? 60;
const renderLine = (ctx: CanvasRenderingContext2D, x: number, width?: number) => {
ctx.beginPath();
ctx.moveTo(x, 0);
ctx.lineTo(x, canvasHeight);
ctx.lineWidth = width || 1;
ctx.stroke();
};

const renderHoliday = (ctx: CanvasRenderingContext2D, t: TimelineTransform, date: Date, x: number, width: number) => {
if (t.isHoliday(date)) {
ctx.fillStyle = 'rgba(249, 209, 204, 0.09)';
ctx.fillRect(x, 0, width, canvasHeight);
return;
}

if (t.isWeekend(date)) {
ctx.fillStyle = '#FBFBFB';
ctx.fillRect(x, 0, width, canvasHeight);
}
};

const renderMinutes = (ctx: CanvasRenderingContext2D, t: TimelineTransform) => {
t.getVisibleMinutes().forEach((w) => {
renderLine(ctx, w.left);
});
};

const renderQuoterHours = (ctx: CanvasRenderingContext2D, t: TimelineTransform) => {
t.getVisibleQuoterHours().forEach((w) => {
renderLine(ctx, w.left);
});
};

const renderHours = (ctx: CanvasRenderingContext2D, t: TimelineTransform) => {
const pxPerHour = (t.pxPerMs * msPerDay) / 24;
const width = pxPerHour > 100 ? 2 : 1;

t.getVisibleHours().forEach((w) => {
renderLine(ctx, w.left, width);
});
};

const renderHolidays = (ctx: CanvasRenderingContext2D, t: TimelineTransform) => {
t.getVisibleDays().forEach((w) => {
renderHoliday(ctx, t, w.leftDate, w.left, w.right - w.left + 1);
});
};

const renderDays = (ctx: CanvasRenderingContext2D, t: TimelineTransform) => {
const pxPerDay = t.pxPerMs * msPerDay;
const width = pxPerDay > 200 ? 2 : 1;

t.getVisibleDays().forEach((w) => {
renderLine(ctx, w.left, width);
});
};
const draw = (context: CanvasRenderingContext2D, timelineTransform: TimelineTransform) => {
context.clearRect(0, 0, timelineTransform.widthPx, canvasHeight);
context.strokeStyle = '#eee';

const renderWeeks = (ctx: CanvasRenderingContext2D, t: TimelineTransform) => {
t.getVisibleWeeks().forEach((w) => {
renderLine(ctx, w.left);
});
};

const renderMonths = (ctx: CanvasRenderingContext2D, t: TimelineTransform) => {
t.getVisibleMonths().forEach((w) => {
renderLine(ctx, w.left);
});
};

const renderYears = (ctx: CanvasRenderingContext2D, t: TimelineTransform) => {
t.getVisibleYears().forEach((w) => {
renderLine(ctx, w.left, 2);
});
};

const renderToday = (ctx: CanvasRenderingContext2D, t: TimelineTransform) => {
ctx.strokeStyle = '#F37B94';
ctx.beginPath();
ctx.moveTo(t.getX(new Date()), 0);
ctx.lineTo(t.getX(new Date()), canvasHeight);
ctx.stroke();
};

const draw = (ctx: CanvasRenderingContext2D, t: TimelineTransform) => {
ctx.clearRect(0, 0, t.widthPx, canvasHeight);
ctx.strokeStyle = '#eee';

const pxPerDay = t.pxPerMs * msPerDay;
const pxPerDay = timelineTransform.pxPerMs * msPerDay;

const drawProps = { context, timelineTransform, canvasHeight };
const customDrawProps = { ...drawProps, drawLine };
if (pxPerDay >= 40000) {
renderMinutes(ctx, t);
const options = drawMinutes ? drawProps : customDrawProps;
(drawMinutes ?? timelineGrid.drawMinutes)(options);
}

if (pxPerDay >= 1600) {
renderQuoterHours(ctx, t);
const options = drawQuoterHours ? drawProps : customDrawProps;
(drawQuoterHours ?? timelineGrid.drawQuoterHours)(options);
}

if (pxPerDay >= 190) {
renderHours(ctx, t);
const options = drawHours ? drawProps : customDrawProps;
(drawHours ?? timelineGrid.drawHours)(options);
}

if (pxPerDay > 10) {
renderDays(ctx, t);
const options = drawDays ? drawProps : customDrawProps;
(drawDays ?? timelineGrid.drawDays)(options);
}

if (pxPerDay > 2 && pxPerDay < 200) {
renderHolidays(ctx, t);
const options = drawHolidays ? drawProps : customDrawProps;
(drawHolidays ?? timelineGrid.drawHolidays)(options);
}

if (pxPerDay > 2) {
renderWeeks(ctx, t);
const options = drawWeeks ? drawProps : customDrawProps;
(drawWeeks ?? timelineGrid.drawWeeks)(options);
}

if (pxPerDay > 0.5) {
renderMonths(ctx, t);
const options = drawWeeks ? drawProps : customDrawProps;
(drawMonths ?? timelineGrid.drawMonths)(options);
}

renderYears(ctx, t);

renderToday(ctx, t);
const options = drawYears ? drawProps : customDrawProps;
(drawYears ?? timelineGrid.drawYears)(options);
(drawToday ?? timelineGrid.drawToday)(drawProps);
};

return <Canvas draw={ restProps.draw ?? draw } canvasHeight={ canvasHeight } timelineController={ timelineController } />;

return (
<Canvas
draw={ restProps.draw ?? draw }
canvasHeight={ canvasHeight }
timelineController={ timelineController }
/>
);
}
143 changes: 143 additions & 0 deletions uui-timeline/src/draw/grid.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,143 @@
import { TimelineTransform } from '../TimelineTransform';
import { msPerDay } from '../helpers';

export interface CommonCanvasDrawProps {
context: CanvasRenderingContext2D;
canvasHeight: number;
}

export interface CanvasDrawLineProps extends CommonCanvasDrawProps {
x: number;
width?: number;
}

export interface CanvasDrawTimelineElementProps extends CommonCanvasDrawProps {
timelineTransform: TimelineTransform;
}

export interface CustomCanvasDrawTimelineElementProps extends CanvasDrawTimelineElementProps {
drawLine?: (props: CanvasDrawLineProps) => void;
}

export interface CanvasDrawHolidayProps extends CanvasDrawLineProps, CanvasDrawTimelineElementProps {
date: Date;
}

export interface CanvasDrawHolidaysProps extends CanvasDrawTimelineElementProps {
drawHolidayOrWeekend?: (props: CanvasDrawHolidayProps) => void;
}

const drawLine = ({ context, x, width, canvasHeight }: CanvasDrawLineProps) => {
context.beginPath();
context.moveTo(x, 0);
context.lineTo(x, canvasHeight);
context.lineWidth = width || 1;
context.stroke();
};

const drawHoliday = ({ context, x, width, canvasHeight }: CanvasDrawLineProps) => {
context.fillStyle = 'rgba(249, 209, 204, 0.09)';
context.fillRect(x, 0, width, canvasHeight);
};

const drawWeekend = ({ context, x, width, canvasHeight }: CanvasDrawLineProps) => {
context.fillStyle = '#FBFBFB';
context.fillRect(x, 0, width, canvasHeight);
};

const drawHolidayOrWeekend = ({ context, x, width, canvasHeight, date, timelineTransform }: CanvasDrawHolidayProps) => {
if (timelineTransform.isHoliday(date)) {
context.fillStyle = 'rgba(249, 209, 204, 0.09)';
context.fillRect(x, 0, width, canvasHeight);
return;
}

if (timelineTransform.isWeekend(date)) {
context.fillStyle = '#FBFBFB';
context.fillRect(x, 0, width, canvasHeight);
}
};

const drawMinutes = ({ context, timelineTransform, canvasHeight, drawLine: customDrawLine }: CustomCanvasDrawTimelineElementProps) => {
timelineTransform.getVisibleMinutes().forEach((w) => {
(customDrawLine ?? drawLine)({ context, x: w.left, canvasHeight });
});
};

const drawQuoterHours = ({ context, timelineTransform, canvasHeight, drawLine: customDrawLine }: CustomCanvasDrawTimelineElementProps) => {
timelineTransform.getVisibleQuoterHours().forEach((w) => {
(customDrawLine ?? drawLine)({ context, x: w.left, canvasHeight });
});
};

const drawHours = ({ context, timelineTransform, canvasHeight, drawLine: customDrawLine }: CustomCanvasDrawTimelineElementProps) => {
const pxPerHour = (timelineTransform.pxPerMs * msPerDay) / 24;
const width = pxPerHour > 100 ? 2 : 1;

timelineTransform.getVisibleHours().forEach((w) => {
(customDrawLine ?? drawLine)({ context, x: w.left, width, canvasHeight });
});
};
const drawHolidays = ({ context, timelineTransform, canvasHeight, drawHolidayOrWeekend: customDrawHolidayOrWeekend }: CanvasDrawHolidaysProps) => {
timelineTransform.getVisibleDays().forEach((w) => {
(customDrawHolidayOrWeekend ?? drawHolidayOrWeekend)({
context,
timelineTransform,
date: w.leftDate,
x: w.left,
width: w.right - w.left + 1,
canvasHeight,
});
});
};

const drawDays = ({ context, timelineTransform, canvasHeight, drawLine: customDrawLine }: CustomCanvasDrawTimelineElementProps) => {
const pxPerDay = timelineTransform.pxPerMs * msPerDay;
const width = pxPerDay > 200 ? 2 : 1;

timelineTransform.getVisibleDays().forEach((w) => {
(customDrawLine ?? drawLine)({ context, x: w.left, width, canvasHeight });
});
};

const drawWeeks = ({ context, timelineTransform, canvasHeight, drawLine: customDrawLine }: CustomCanvasDrawTimelineElementProps) => {
timelineTransform.getVisibleWeeks().forEach((w) => {
(customDrawLine ?? drawLine)({ context, x: w.left, canvasHeight });
});
};

const drawMonths = ({ context, timelineTransform, canvasHeight, drawLine: customDrawLine }: CustomCanvasDrawTimelineElementProps) => {
timelineTransform.getVisibleMonths().forEach((w) => {
(customDrawLine ?? drawLine)({ context, x: w.left, canvasHeight });
});
};

const drawYears = ({ context, timelineTransform, canvasHeight, drawLine: customDrawLine }: CustomCanvasDrawTimelineElementProps) => {
timelineTransform.getVisibleYears().forEach((w) => {
(customDrawLine ?? drawLine)({ context, x: w.left, width: 2, canvasHeight });
});
};

const drawToday = ({ context, timelineTransform, canvasHeight }: CanvasDrawTimelineElementProps) => {
context.strokeStyle = '#F37B94';
context.beginPath();
context.moveTo(timelineTransform.getX(new Date()), 0);
context.lineTo(timelineTransform.getX(new Date()), canvasHeight);
context.stroke();
};

export const timelineGrid = {
drawLine,
drawHoliday,
drawWeekend,
drawHolidayOrWeekend,
drawMinutes,
drawQuoterHours,
drawHours,
drawHolidays,
drawDays,
drawWeeks,
drawMonths,
drawYears,
drawToday,
};
1 change: 1 addition & 0 deletions uui-timeline/src/draw/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './grid';

0 comments on commit 25ad078

Please sign in to comment.