Improve Supply event chart style

This commit is contained in:
Sakura Knoll
2022-07-21 00:52:47 +09:00 Unverified
parent b083ed476e
commit 9f09dc5aa8
+155 -128
View File
@@ -6,10 +6,9 @@ import {
differenceInCalendarDays, differenceInCalendarDays,
differenceInCalendarWeeks, differenceInCalendarWeeks,
format, format,
subDays,
} from 'date-fns' } from 'date-fns'
import { times } from 'ramda' import { times } from 'ramda'
import { useMemo, MouseEventHandler } from 'react' import React, { useMemo, MouseEventHandler } from 'react'
export interface GanttChartItem { export interface GanttChartItem {
id: string id: string
@@ -26,6 +25,11 @@ interface GanttChartProps {
items: GanttChartItem[] items: GanttChartItem[]
} }
const widthOfDay = 20
const widthOfWeek = widthOfDay * 7
const itemHeight = 30
const GanttChart = ({ const GanttChart = ({
startDate: startDateString, startDate: startDateString,
endDate: endDateString, endDate: endDateString,
@@ -34,8 +38,8 @@ const GanttChart = ({
}: GanttChartProps) => { }: GanttChartProps) => {
const startDate = new Date(startDateString) const startDate = new Date(startDateString)
const endDate = new Date(endDateString) const endDate = new Date(endDateString)
const firstDateToRender = subDays(startDate, startDate.getDay() - 1) const firstDateToRender = startDate
const lastDateToRender = addDays(endDate, 6 - endDate.getDay() + 1) const lastDateToRender = endDate
const todayDate = new Date(todayDateString) const todayDate = new Date(todayDateString)
const daysToRender = differenceInCalendarDays( const daysToRender = differenceInCalendarDays(
@@ -54,91 +58,55 @@ const GanttChart = ({
}, [items]) }, [items])
return ( return (
<Box sx={{ width: weeksToRender * 280 + 70 }}> <Box
<Flex sx={{ width: weeksToRender * widthOfWeek + 70, marginLeft: widthOfDay }}
sx={{ >
marginLeft: -20, <WeekLabelRow
}} firstDateToRender={firstDateToRender}
> weeksToRender={weeksToRender}
{times((index) => { />
const weekNumber = index + 1
return (
<Box
key={`week-${weekNumber}`}
sx={{
width: 280,
textAlign: 'center',
fontWeight: 700,
}}
>
Week {weekNumber}
</Box>
)
}, weeksToRender)}
</Flex>
<Box <Box
sx={{ sx={{
position: 'relative', position: 'relative',
height: totalRow * 50 + 40, height: totalRow * (itemHeight + 10) + 30,
borderBottomStyle: 'solid',
borderBottomWidth: 1,
borderBottomColor: 'border',
borderTopStyle: 'solid',
borderTopWidth: 1,
borderTopColor: 'border',
}} }}
> >
{times((index) => { {times((index) => {
return ( return (
<Box <DateMeasure
key={`day-border-${index}`} key={`day-border-${index}`}
sx={{ index={index}
position: 'absolute', totalRow={totalRow}
height: totalRow * 50 + 40,
borderRightStyle: 'solid',
borderRightWidth: 1,
borderRightColor: index % 7 === 6 ? 'border' : 'altBorder',
left: (index + 1) * 40 - 1 - 20,
}}
/> />
) )
}, daysToRender + 1)} }, daysToRender)}
{times((index) => { {times((index) => {
const weekNumber = index + 1
return ( return (
<Text <Box
key={`week-start-date-${index}`} key={`weekdate-${index}`}
sx={{ sx={{
position: 'absolute', position: 'absolute',
color: 'border', left: (index - 1) * widthOfDay,
zIndex: 21, width: widthOfDay,
top: 0, textAlign: 'center',
left: weekNumber * 280 - 15, color:
width: 300, index - (1 % 7) === 3
pointerEvents: 'none', ? 'red'
: index - (1 % 7) === 2
? 'blue'
: 'default',
}} }}
> >
{format(addWeeks(firstDateToRender, weekNumber), 'PP')} {format(addDays(firstDateToRender, index - 1), 'EEEEE')}
</Text> </Box>
) )
}, weeksToRender - 1)} }, daysToRender + 2)}
<Box
sx={{ <TodayBox
boxSizing: 'border-box', totalRow={totalRow}
position: 'absolute', todayDate={todayDate}
width: 40, firstDateToRender={firstDateToRender}
height: totalRow * 50 + 40,
backgroundColor: 'blue.5',
borderStyle: 'solid',
borderColor: 'blue.7',
opacity: 0.2,
zIndex: 20,
borderRadius: 4,
left:
differenceInCalendarDays(todayDate, firstDateToRender) * 40 - 20,
pointerEvents: 'none',
}}
/> />
<Box <Box
@@ -146,22 +114,11 @@ const GanttChart = ({
boxSizing: 'border-box', boxSizing: 'border-box',
position: 'absolute', position: 'absolute',
width: 1, width: 1,
height: totalRow * 50 + 40, height: totalRow * (itemHeight + 10) + itemHeight,
backgroundColor: 'red.3', backgroundColor: 'red.3',
zIndex: 20, zIndex: 20,
left: differenceInCalendarDays(startDate, firstDateToRender) * 40, left:
pointerEvents: 'none', differenceInCalendarDays(endDate, firstDateToRender) * widthOfDay,
}}
/>
<Box
sx={{
boxSizing: 'border-box',
position: 'absolute',
width: 1,
height: totalRow * 50 + 40,
backgroundColor: 'red.3',
zIndex: 20,
left: differenceInCalendarDays(endDate, firstDateToRender) * 40,
pointerEvents: 'none', pointerEvents: 'none',
}} }}
/> />
@@ -171,25 +128,11 @@ const GanttChart = ({
transform: 'rotate(90deg)', transform: 'rotate(90deg)',
color: 'red.5', color: 'red.5',
zIndex: 21, zIndex: 21,
top: 150, top: 170,
left: left:
differenceInCalendarDays(startDate, firstDateToRender) * 40 + differenceInCalendarDays(endDate, firstDateToRender) *
-160, widthOfDay +
width: 300, -140,
pointerEvents: 'none',
}}
>
{format(startDate, 'PP')}
</Text>
<Text
sx={{
position: 'absolute',
transform: 'rotate(90deg)',
color: 'red.5',
zIndex: 21,
top: 150,
left:
differenceInCalendarDays(endDate, firstDateToRender) * 40 + -140,
width: 300, width: 300,
pointerEvents: 'none', pointerEvents: 'none',
}} }}
@@ -197,41 +140,25 @@ const GanttChart = ({
{format(endDate, 'PP')} {format(endDate, 'PP')}
</Text> </Text>
<Text
sx={{
position: 'absolute',
color: 'blue.7',
transform: 'rotate(90deg)',
zIndex: 21,
top: 150,
left:
differenceInCalendarDays(new Date(todayDate), firstDateToRender) *
40 -
150,
width: 300,
pointerEvents: 'none',
}}
>
Today ({format(todayDate, 'PP')})
</Text>
{items.map((item) => { {items.map((item) => {
const offset = const offset =
differenceInCalendarDays( differenceInCalendarDays(
new Date(item.duration[0]), new Date(item.duration[0]),
firstDateToRender firstDateToRender
) * 40 ) *
widthOfDay -
widthOfDay / 2
const length = const length =
differenceInCalendarDays( differenceInCalendarDays(
new Date(item.duration[1]), new Date(item.duration[1]),
new Date(item.duration[0]) new Date(item.duration[0])
) * 40 ) * widthOfDay
return ( return (
<Flex <Flex
key={item.id} key={item.id}
py={2} py={2}
px={3} px={2}
sx={{ sx={{
boxSizing: 'border-box', boxSizing: 'border-box',
position: 'absolute', position: 'absolute',
@@ -241,13 +168,13 @@ const GanttChart = ({
backgroundColor: 'background', backgroundColor: 'background',
width: length, width: length,
left: offset, left: offset,
top: (item.row - 1) * 50 + 20, top: (item.row - 1) * (itemHeight + 10) + 30,
overflow: 'hidden', overflow: 'hidden',
textOverflow: 'ellipsis', textOverflow: 'ellipsis',
whiteSpace: 'nowrap', whiteSpace: 'nowrap',
height: 40, height: itemHeight,
borderRadius: 40, borderRadius: itemHeight / 2,
fontWeight: 700, fontSize: 1,
zIndex: 10, zIndex: 10,
'&:hover': { '&:hover': {
minWidth: length, minWidth: length,
@@ -268,3 +195,103 @@ const GanttChart = ({
} }
export default GanttChart export default GanttChart
const WeekLabelRow = ({
weeksToRender,
firstDateToRender,
}: {
weeksToRender: number
firstDateToRender: Date
}) => {
return (
<Flex sx={{}}>
{times((index) => {
const weekNumber = index
return (
<Box
key={`week-${weekNumber}`}
sx={{
width: widthOfWeek,
color: 'textMuted',
}}
>
{format(addWeeks(firstDateToRender, weekNumber), 'PP')}
</Box>
)
}, weeksToRender)}
</Flex>
)
}
const DateMeasure = ({
index,
totalRow,
}: {
index: number
totalRow: number
}) => {
return (
<Box
key={`day-border-${index}`}
sx={{
position: 'absolute',
height: totalRow * 50 + widthOfDay,
borderRightStyle: index % 7 === 0 ? 'solid' : 'dashed',
borderRightWidth: 1,
borderRightColor: index % 7 === 0 ? 'border' : 'altBorder',
left: index * widthOfDay,
}}
/>
)
}
const TodayBox = ({
totalRow,
todayDate,
firstDateToRender,
}: {
totalRow: number
todayDate: Date
firstDateToRender: Date
}) => {
return (
<>
<Text
sx={{
position: 'absolute',
color: 'blue.7',
transform: 'rotate(90deg)',
zIndex: 21,
top: 170,
left:
differenceInCalendarDays(new Date(todayDate), firstDateToRender) *
widthOfDay -
160,
width: 300,
pointerEvents: 'none',
}}
>
Today ({format(todayDate, 'PP')})
</Text>
<Box
sx={{
boxSizing: 'border-box',
position: 'absolute',
width: widthOfDay,
height: totalRow * (itemHeight + 10) + itemHeight,
backgroundColor: 'blue.5',
borderStyle: 'solid',
borderColor: 'blue.7',
borderRadius: 4,
opacity: 0.3,
zIndex: 20,
left:
differenceInCalendarDays(todayDate, firstDateToRender) *
widthOfDay -
20,
pointerEvents: 'none',
}}
/>
</>
)
}