UNPKG

vue-gantt-3

Version:

A gantt component for Vue 3

1 lines 16 kB
{"version":3,"file":"GanttHeader.vue.mjs","sources":["../../../../../src/components/ganttView/ganttHeader/GanttHeader.vue"],"sourcesContent":["<template>\n <div ref=\"ganttHeaderRef\" class=\"vg-header\">\n <div v-show=\"showFirstLevel || !showSecondLevel\" class=\"vg-header-first-level \" :style=\"{width: ganttHeaderLevelWidth, height: `${headerHeight + 1}px`}\">\n <div v-for=\"item in firstLevelBlocks\"\n :key=\"item.key\"\n class=\"vg-header-block\"\n :class=\"{'vg-header-block-hide-right-border': item.hideRightBorder}\"\n :title=\"item.tip\"\n :style=\"{width: item.width + 'px', left: item.left + 'px'}\">\n <span class=\"vg-header-block-text\">{{ item.text }}</span>\n </div>\n </div>\n <div v-show=\"showSecondLevel\" class=\"vg-header-second-level\" :style=\"{width: ganttHeaderLevelWidth, height: `${headerHeight + 1}px`}\">\n <div v-for=\"item in secondLevelBlocks\"\n :key=\"item.key\"\n class=\"vg-header-block\"\n :class=\"{'vg-header-block-hide-right-border': item.hideRightBorder}\"\n :title=\"item.tip\"\n :style=\"{width: item.width + 'px', left: item.left + 'px'}\">\n <span class=\"vg-header-block-text\">{{ item.text }}</span>\n </div>\n </div>\n </div>\n</template>\n<script lang=\"ts\" setup>\nimport dayjs from 'dayjs';\nimport { ref, inject, computed, watch, shallowRef } from 'vue';\nimport type { Ref } from 'vue';\n\nimport quarterOfYear from 'dayjs/plugin/quarterOfYear';\nimport type { GanttHeaderUnit, BlockItem } from '@/types';\nimport { getRound } from '@/utils/common';\nimport lang from '@/locale';\n\ndayjs.extend(quarterOfYear);\n\nexport interface Props {\n headerHeight: number,\n edgeSpacing: number,\n perHourSpacing: number,\n ganttMinDate: dayjs.Dayjs,\n ganttViewWidth: number,\n locale?: string,\n headerTextRender?: (date: dayjs.Dayjs, unit: GanttHeaderUnit) => string | number,\n headerTipRender?: (date: dayjs.Dayjs, unit: GanttHeaderUnit) => string,\n}\n\nconst props = defineProps<Props>();\n\nconst firstLevelBlocks = shallowRef<BlockItem[]>([]);\nconst secondLevelBlocks = shallowRef<BlockItem[]>([]);\nconst units: GanttHeaderUnit[] = ['hour', 'day', 'week', 'month', 'quarter', 'year'];\nconst scrollViewScrollLeft = ref(0);\nconst bufferWidth = 200;\nconst ganttHeaderRef = ref<HTMLDivElement>();\nconst scrollLeftOffset = ref(0);\nconst showSecondLevel = inject('showSecondLevel') as Ref<boolean>;\nconst showFirstLevel = inject('showFirstLevel') as Ref<boolean>;\n\nconst localeRef = computed(() => {\n if (props.locale) {\n return props.locale;\n } else {\n const language = navigator.language;\n if (language.startsWith('zh')) {\n return 'zh-cn';\n } else {\n return language;\n }\n }\n});\n\nconst ganttHeaderLevelWidth = computed(() => {\n if (!ganttHeaderRef.value) return '100%';\n const minWidth = ganttHeaderRef.value.offsetWidth as number;\n return Math.max(minWidth, props.ganttViewWidth + scrollLeftOffset.value) + 'px';\n});\n\nconst getUnit = computed(() => {\n const { perHourSpacing } = props;\n let firstLevelUnitIndex = 0;\n const perMonthSpacing = perHourSpacing * 24 * 30;\n let canShowSecondLevel = true;\n\n if (perMonthSpacing >= 30000) {\n firstLevelUnitIndex = units.indexOf('day');\n } else if (perMonthSpacing >= 800) {\n firstLevelUnitIndex = units.indexOf('week');\n } else if (perMonthSpacing >= 400) {\n firstLevelUnitIndex = units.indexOf('month');\n } else if (perMonthSpacing >= 40) {\n firstLevelUnitIndex = units.indexOf('quarter');\n } else if (perMonthSpacing >= 24) {\n firstLevelUnitIndex = units.indexOf('year');\n } else if (perMonthSpacing >= 5) {\n firstLevelUnitIndex = units.indexOf('year');\n canShowSecondLevel = false;\n }\n\n return {\n firstLevelUnit: units[firstLevelUnitIndex],\n secondLevelUnit: units[firstLevelUnitIndex - 1],\n canShowSecondLevel\n };\n});\n\nconst startInfo = computed(() => {\n const { perHourSpacing, edgeSpacing, ganttMinDate } = props;\n const { firstLevelUnit, secondLevelUnit } = getUnit.value;\n const diffSpacing = edgeSpacing / perHourSpacing;\n const startDate = ganttMinDate.subtract(diffSpacing, 'hour');\n\n const firstLevelStartUnitDate = startDate.endOf(firstLevelUnit);\n const secondLevelStartUnitDate = startDate.endOf(secondLevelUnit);\n\n const firstLevelStartLeft = firstLevelStartUnitDate.diff(startDate, 'hour', true) * perHourSpacing;\n const secondLevelStartLeft = secondLevelStartUnitDate.diff(startDate, 'hour', true) * perHourSpacing;\n\n return {\n firstLevelStartUnitDate,\n secondLevelStartUnitDate,\n firstLevelStartLeft,\n secondLevelStartLeft\n };\n\n});\n\nconst freshBlocks = () => {\n if (!ganttHeaderRef.value) return;\n const { firstLevelStartUnitDate, secondLevelStartUnitDate, firstLevelStartLeft, secondLevelStartLeft } = startInfo.value;\n\n const { firstLevelUnit, secondLevelUnit, canShowSecondLevel } = getUnit.value;\n\n // first header\n firstLevelBlocks.value = getNewBlocks(firstLevelStartLeft, firstLevelStartUnitDate, firstLevelUnit);\n\n // second header\n showSecondLevel.value = canShowSecondLevel;\n if (canShowSecondLevel) {\n secondLevelBlocks.value = getNewBlocks(secondLevelStartLeft, secondLevelStartUnitDate, secondLevelUnit);\n }\n};\n\n/**\n * calculate blocks' size by startLeft and startDate\n * @param startLeft\n * @param startDate\n * @param currentUnit\n */\nconst getNewBlocks = (startLeft: number, startDate: dayjs.Dayjs, currentUnit: GanttHeaderUnit) => {\n const ganttHeaderWidth = ganttHeaderRef.value!.offsetWidth;\n const startLeftInView = scrollViewScrollLeft.value - bufferWidth;\n const endLeftInView = scrollViewScrollLeft.value + ganttHeaderWidth + bufferWidth;\n const { perHourSpacing } = props;\n\n const newLevelBlocks: BlockItem[] = [];\n let levelStart = startLeft;\n let levelStartDateInView = startDate;\n if (startLeftInView > startLeft) {\n const diffHour = (startLeftInView - startLeft) / perHourSpacing;\n const startDateInView = startDate.add(diffHour, 'hour');\n const endDateInView = startDateInView.endOf(currentUnit);\n const diff = endDateInView.diff(startDate, 'hour', true);\n levelStart = startLeft + diff * perHourSpacing;\n levelStartDateInView = endDateInView;\n }\n\n let currentLevelStartDateInView = levelStartDateInView;\n const limitMinLeft = scrollViewScrollLeft.value;\n const limintMaxLeft = scrollViewScrollLeft.value + ganttHeaderWidth;\n let blockSpacing = getBlockSpacingByUnit(currentLevelStartDateInView, currentUnit);\n\n while ((levelStart - blockSpacing) <= endLeftInView) {\n let width = blockSpacing;\n let offset = width;\n let hideRightBorder = false;\n if (levelStart > limitMinLeft && (levelStart - blockSpacing) < limitMinLeft) {\n offset = width = levelStart - limitMinLeft;\n if (width > ganttHeaderWidth) {\n width = ganttHeaderWidth;\n hideRightBorder = true;\n }\n } else if (levelStart > limintMaxLeft && (levelStart - blockSpacing) < limintMaxLeft) {\n width = blockSpacing - (levelStart - limintMaxLeft);\n hideRightBorder = true;\n }\n newLevelBlocks.push({\n left: getRound(levelStart - offset),\n width: getRound(width),\n text: getBlockText(currentLevelStartDateInView, currentUnit),\n key: getRound(levelStart),\n tip: getBlockTip(currentLevelStartDateInView, currentUnit),\n hideRightBorder\n });\n currentLevelStartDateInView = currentLevelStartDateInView.add(1, currentUnit).endOf(currentUnit);\n blockSpacing = getBlockSpacingByUnit(currentLevelStartDateInView, currentUnit);\n levelStart += blockSpacing;\n\n }\n return newLevelBlocks;\n};\n\nconst getBlockText = (date: dayjs.Dayjs, unit: GanttHeaderUnit) => {\n if (props.headerTextRender) {\n return props.headerTextRender(date, unit);\n }\n const currentLang = lang[localeRef.value];\n switch (unit) {\n case 'hour':\n return date.hour();\n case 'day':\n return date.date();\n case 'month':\n return currentLang.month[date.month() + 1];\n case 'year':\n return date.year();\n case 'week':\n return `${date.startOf('week').format('YYYY.MM.DD')}-${date.endOf('week').format('YYYY.MM.DD')}`;\n case 'quarter':\n return `${currentLang.month[date.startOf('quarter').month() + 1]}-${currentLang.month[date.endOf('quarter').month() + 1]}`;\n }\n\n};\n\nconst getBlockTip = (date: dayjs.Dayjs, unit: GanttHeaderUnit) => {\n if (props.headerTipRender) {\n return props.headerTipRender(date, unit);\n }\n const dateFormat = lang[localeRef.value].dateFormat;\n switch (unit) {\n case 'hour':\n return date.format(dateFormat['hour']);\n case 'day':\n return date.format(dateFormat['day']);\n case 'month':\n return date.format(dateFormat['month']);\n case 'year':\n return date.format(dateFormat['year']);\n case 'week':\n return `${date.startOf('week').format('YYYY.MM.DD')}-${date.endOf('week').format('YYYY.MM.DD')}`;\n case 'quarter':\n return `${date.startOf('quarter').format(dateFormat['month'])}-${date.endOf('quarter').format(dateFormat['month'])}`;\n }\n\n};\n\nconst getBlockSpacingByUnit = (date: dayjs.Dayjs, unit: GanttHeaderUnit) => {\n const { perHourSpacing } = props;\n\n switch (unit) {\n case 'hour':\n return perHourSpacing;\n case 'day':\n return perHourSpacing * 24;\n case 'week':\n return perHourSpacing * 24 * 7;\n }\n\n const startDate = date.startOf(unit);\n const diffHour = date.diff(startDate, 'hour', true);\n return diffHour * perHourSpacing;\n};\n\nwatch([localeRef, startInfo, scrollViewScrollLeft], freshBlocks);\n\nconst onScroll = ({ scrollLeft }: { scrollLeft: number}) => {\n scrollViewScrollLeft.value = scrollLeft;\n ganttHeaderRef.value && (ganttHeaderRef.value.scrollLeft = scrollLeft);\n};\n\nconst updateGanttHeaderWidth = (show: boolean, scrollbarWidth: number) => {\n if (show) {\n scrollLeftOffset.value = scrollbarWidth;\n } else {\n scrollLeftOffset.value = 0;\n }\n};\n\nconst onResize = () => {\n freshBlocks();\n\n};\n\ndefineExpose({\n onScroll,\n updateGanttHeaderWidth,\n onResize\n});\n\n</script>\n\n<style lang=\"scss\">\n.vg-header {\n min-width: 100%;\n max-width: 100%;\n overflow: hidden;\n color: #000;\n .vg-header-first-level, .vg-header-second-level {\n position: relative;\n\n .vg-header-block {\n position: absolute;\n height: 100%;\n display: flex;\n justify-content: center;\n align-items: center;\n border-right: 1px solid #e9e9e9;\n border-bottom: 1px solid #e9e9e9;\n .vg-header-block-text {\n text-overflow: ellipsis;\n white-space: nowrap;\n overflow: hidden;\n }\n &.vg-header-block-hide-right-border {\n border-right: none;\n }\n }\n }\n}\n</style>"],"names":[],"mappings":"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"}