Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix issues, add new features. #130

Open
wants to merge 18 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -29,3 +29,6 @@ docs/.vitepress/temp
docs/.vitepress/dist

*.tgz

# Package manager
.npmrc
41 changes: 25 additions & 16 deletions docs/GGanttChart.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,22 +6,31 @@ The main component of Vue Ganttastic. Represents an entire chart and is meant to
| `chart-start` | string | | Start date-time of the chart.
| `chart-end` | string | | End date-time of the chart.
| `precision` | string? | `"hour"` | Display precision of the time-axis. Possible values: `hour`, `day`, `date`, `week` and `month`. |
| `bar-start` | string | | Name of the property in bar objects that represents the start date.
| `bar-end` | string | | Name of the property in bar objects that represents the end date .
| `date-format` | string \| false | `"YYYY-MM-DD HH:mm"` | Datetime string format of `chart-start`, `chart-end` and the values of the `bar-start`, `bar-end` properties in bar objects. See [Day.js format tokens](https://day.js.org/docs/en/parse/string-format). If the aforementioned properties are native JavaScript [Date](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date) objects in your use case, pass `false`.
| `width` | string? | `"100%"` | Width of the chart (e.g. `80%` or `800px`)
| `hide-timeaxis` | boolean? | `false` | Toggle visibility of the time axis.
| `color-scheme` | string \| ColorScheme | `"default"` | Color scheme (theme) of the chart. Either use the name of one of the predefined schemes or pass a color-scheme-object of your own. See [color schemes](#color-schemes).
| `grid` | string? | `false` | Toggle visibility of background grid.
| `current-time` | boolean? | `false` | Toggle visibility of current time marker.
| `current-time-label` | string? | `''` | Text to be displayed next to the current time marker.
| `push-on-overlap` | boolean? | `false` | Specifies whether bars "push one another" when dragging and overlaping.
| `no-overlap` | boolean? | `false` | If `push-on-overlap` is `false`, toggle this to prevent overlaps after drag by snapping the dragged bar back to its original position.
| `row-height` | number? | `40` | Height of each row in pixels.
| `highlighted-units` | number[]? | `[]` | The time units specified here will be visually highlighted in the chart with a mild opaque color.
| `font` | string | `"Helvetica"`| Font family of the chart.
| `label-column-title` | string? | `''` | If specified, a dedicated column for the row labels will be rendered on the left side of the graph. The specified title is displayed in the upper left corner, as the column's header.
| `label-column-width` | string? | `150px` | Width of the column containing the row labels (if `label-column-title` specified)
| `bar-start` | string | | Name of the property in bar objects that represents the start date. |
| `bar-end` | string | | Name of the property in bar objects that represents the end date . |
| `date-format` | string \| false | `"YYYY-MM-DD HH:mm"` | Datetime string format of `chart-start`, `chart-end` and the values of the `bar-start`, `bar-end` properties in bar objects. See [Day.js format tokens](https://day.js.org/docs/en/parse/string-format). If the aforementioned properties are native JavaScript [Date](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date) objects in your use case, pass `false`. |
| `width` | string? | `"100%"` | Width of the chart (e.g. `80%` or `800px`) |
| `hide-timeaxis` | boolean? | `false` | Toggle visibility of the time axis. |
| `color-scheme` | string \| ColorScheme | `"default"` | Color scheme (theme) of the chart. Either use the name of one of the predefined schemes or pass a color-scheme-object of your own. See [color schemes](#color-schemes). |
| `grid` | string? | `false` | Toggle visibility of background grid. |
| `current-time` | boolean? | `false` | Toggle visibility of current time marker. |
| `current-time-label` | string? | `''` | Text to be displayed next to the current time marker. |
| `push-on-overlap` | boolean? | `false` | Specifies whether bars "push one another" when dragging and overlaping. |
| `no-overlap` | boolean? | `false` | If `push-on-overlap` is `false`, toggle this to prevent overlaps after drag by snapping the dragged bar back to its original position. |
| `row-height` | number? | `40` | Height of each row in pixels. |
| `highlighted-units` | number[]? | `[]` | The time units specified here will be visually highlighted in the chart with a mild opaque color. Make sure to also use the `grid` prop on the chart. |
| `highlighted-days-of-week` | number[]? | `[]` | When using `precision = day` or `date`, set this array to the days of the week that should be highlighted. Sunday = 0. So to highlight weekends, use `[0, 6]`. Can be combined with `highlighted-dates`. Make sure to also use the `grid` prop on the chart. |
| `highlighted-dates` | number[]? | `[]` | When using `precision = day` or `date`, set this array to the dates that should be highlighted. e.g. `[1, 15, 23]` to highlight the 1st, 15th and 23rd. Can be combined with `highlighted-days-of-week`. Make sure to also use the `grid` prop on the chart. |
| `highlighted-hours` | number[]? | `[]` | When using `precision = hour` set this array to the hours that should be highlighted. Make sure to also use the `grid` prop on the chart. |
| `font` | string | `"Helvetica"`| Font family of the chart. |
| `label-column-title` | string? | `''` | If specified, a dedicated column for the row labels will be rendered on the left side of the graph. The specified title is displayed in the upper left corner, as the column's header. |
| `label-column-width` | string? | `150px` | Width of the column containing the row labels (if `label-column-title` specified) |
| `showDayName` | boolean? | `true` | Adds the Day name to the timeunit axis when in `day` or `date` mode |
| `dayNameLength` | string? | `short` | Sets whether the day name is short or long eg. 'Fri' or 'Friday'. Possible values: `short`, `long` |
| `locale` | string? | `en-GB` | Used when getting the day name only. |
| `allowRightClickDragging` | boolean? | `false` | Enable or disable the ability to drag bars when right-clicking a bar. Useful if you want to use the context menu and prevent accidental bar movements. |
| `disableDragging` | boolean? | `false` | Disable dragging for all bars in the chart. |
| `showLabelAsTooltipTitle` | boolean? | `true` | Toggles showing each bar item's label as the title in the hover tooltip. Make sure to sanitize your labels. |


## Custom Events
Expand Down
7 changes: 5 additions & 2 deletions docs/GGanttRow.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,17 @@ Represents a single row of the chart. It is meant to be a child component of `g-
## Props
| Prop | Type | Default | Description |
|-------------|---------|---------|------------------------------|
| `id` | `string, number` | | Used in the `click-label` event.
| `label` |`string?`| `""` | Text that is floating in the upper left corner of the row.
| `bars` |`GanttBarObject[]`| | Array of objects, each representing a bar in this row. Any JavaScript/TypeScript object with a nested `ganttBarConfig` object with a unique `id` string property is compatible. The objects must also contain two properties which represent the start and end datetime of the bar. The names of those properties must be passed to the `bar-start` and `bar-end` props of the `g-gantt-chart` parent.
| `highlight-on-hover` | `boolean?` | `false` | Used for toggling a background color transition effect on mouse hover.
| `bars` |`GanttBarObject[]`| | Array of objects, each representing a bar in this row. Any JavaScript/TypeScript object with a nested `ganttBarConfig` object with a unique `id` string property is compatible. The objects must also contain two properties which represent the start and end datetime of the bar. The names of those properties must be passed to the `bar-start` and `bar-end` props of the `g-gantt-chart` parent. |
| `highlight-on-hover` | `boolean?` | `false` | Used for toggling a background color transition effect on mouse hover. |
| `disableDragging` | `boolean?` | `false` | Used to disable dragging on a per-row basis. You can still disable dragging on a per-bar basis by setting `immobile` in the `GanttBarConfig` object of your bar object. Note that bar bundles ignore the immobile flag. If you drag an immobile bar in a bundle, the dragging will be prevented. If you drag a mobile bar in the same bundle, the immobile bars will also move. You can disable dragging entirely by setting `disableDragging` at the Chart level. |

## Custom Events
| Event name | Event data |
|----------------------------|------------------------------------------------------------|
| `drop` | `{ e: MouseEvent, datetime: string}` |
| `click-label` | `{ e: MouseEvent, label: string, id?: string | number }` |


## Slots
Expand Down
2 changes: 1 addition & 1 deletion docs/common-use-cases.md
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,7 @@ const onDrop = (e: MouseEvent, datetime?: string) => {
If the time-range (`chart-start` to `chart-end`) of your chart is very large, the displayed time units in the time axis might be too dense if the chart is not wide enough. You might want to specify the precision of the time axis accordingly. Use the `precision` prop of `g-gantt-chart` for this. Possible values are `hour`, `day`, `week` and `month`.

## Chart themes
Vue Ganttastic ships with several pre-made color schemes that you may specify using the `color-scheme` prop of `g-gantt-chart`. [List of available color-schemes](https://infectoone.github.io/vue-ganttastic/GGanttChart.html#color-schemes)
Vue Ganttastic ships with several pre-made color schemes that you may specify using the `color-scheme` prop of `g-gantt-chart`. [List of available color-schemes](https://zunnzunn.github.io/vue-ganttastic/GGanttChart.html#color-schemes)

## Locale
Since Vue Ganttastic uses Day.js for all datetime manipulations, you can change the locale of Vue Ganttastic by [changing the global locale of Day.js](https://day.js.org/docs/en/i18n/changing-locale). You will usually do this in your `src/main.js` before you initialize the Ganttastic plugin.
Expand Down
20 changes: 20 additions & 0 deletions docs/ganttBarConfig.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# ganttBarConfig type
The ganttBarConfig object allows customization of the bar objects and how they behave.

You can add new properties as you wish, but the following properties already exist, and will change how your bars behave.

## Properties
| Property | Type | Description |
| -------- | ---- | ----------- |
| `id` | string | An identifier for the bar |
| `label` | string? | The label for the bar. Can also be shown in the bar's tooltip if you set the `showLabelAsTooltipTitle` prop on the GGanttChart. Make sure to sanitize the value. |
| `subtitle` | string? | If set, this will be appended to the tooltip. Make sure to sanitize the value. |
| `html` | string? | Will render HTML immediately next to the label. Make sure to sanitize the value. |
| `hasHandles` | boolean? | Toggles the bars drag handles allowing user to adjust start and end times independently. |
| `immobile` | boolean? | Toggle an individual bar's ability to be dragged. Note that if an immobile bar is in a bundle with a mobile bar, dragging the mobile bar will also move the immobile bar. Immobile disables direct user interaction. |
| `bundle` | string? | Group bars together such that dragging any bar in the same bundle will also move all other bars in that bundle. |
| `pushOnOverlap` | boolean? | Prevents bars from overlapping each other by pushing other bars that would overlap out of the way. |
| `dragLimitLeft` | number? | |
| `dragLimitRight` | number? | |
| `style` | Object<CSSProperties> | The style for each bar. |
| `class` | string? | The class to be applied to each bar. |
2 changes: 1 addition & 1 deletion docs/getting-started.md
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ const row2BarList = ref([
</script>
```

The result shoud look like this:
The result should look like this:
<g-gantt-chart chart-start="2021-07-12 12:00" chart-end="2021-07-14 12:00" precision="hour" width="100%" bar-start="myBeginDate" bar-end="myEndDate"> <g-gantt-row label="My row 1" :bars="row1BarList"/>
<g-gantt-row label="My row 2" :bars="row2BarList"/>
</g-gantt-chart>
Expand Down
14 changes: 13 additions & 1 deletion src/GanttPlayground.vue
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,11 @@
<g-gantt-chart
:chart-start="chartStart"
:chart-end="chartEnd"
precision="week"
precision="day"
:row-height="40"
:highlighted-hours="[0, 1, 8, 22, 23]"
:highlighted-days-of-week="[0, 6]"
:highlighted-dates="[4, 6]"
grid
current-time
width="100%"
Expand All @@ -24,9 +27,11 @@
<g-gantt-row label="My another new row to test" highlight-on-hover :bars="bars2" />
<g-gantt-row label="just another row to test gantt" highlight-on-hover :bars="bars3" />
<g-gantt-row
id="some-unique-id"
label="errors teach us, and debugging makes us stronger!"
highlight-on-hover
:bars="bars4"
@click-label="onLabelClick"
/>
</g-gantt-chart>

Expand All @@ -45,6 +50,10 @@ const chartEnd = ref(
dayjs(chartStart.value, format.value).add(3, "days").hour(12).format(format.value)
)

const onLabelClick = (e: MouseEvent) => {
console.log("click-label", e)
}

const bars1 = ref<GanttBarObject[]>([
{
beginDate: dayjs().hour(13).startOf("hour").format(format.value),
Expand Down Expand Up @@ -88,6 +97,9 @@ const bars2 = ref([
ganttBarConfig: {
id: "9716981641",
label: "Oh hey",
subtitle: "I'm a subtitle",
html: "<strong>HTML</strong> content",
hasHandles: true,
style: {
background: "#69e064",
borderRadius: "15px",
Expand Down
44 changes: 37 additions & 7 deletions src/components/GGanttBar.vue
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,15 @@
@mouseleave="onMouseEvent"
@contextmenu="onMouseEvent"
>
<div class="g-gantt-bar-label">
<slot :bar="bar">
<div>
{{ barConfig.label || "" }}
</div>
<div v-if="barConfig.html" v-html="barConfig.html"/>
</slot>
<div class="g-gantt-bar-label-container" :style="labelPosition">
<div class="g-gantt-bar-label">
<slot :bar="bar">
<div>
{{ barConfig.label || "" }}
</div>
<div v-if="barConfig.html" v-html="barConfig.html"/>
</slot>
</div>
</div>
<template v-if="barConfig.hasHandles">
<div class="g-gantt-bar-handle-left" />
Expand Down Expand Up @@ -105,6 +107,34 @@ const { barStart, barEnd, width, chartStart, chartEnd, chartSize } = config
const xStart = ref(0)
const xEnd = ref(0)

// Position bar label to the center of the visible part of the chart
const labelPosition = computed((): Record<string, string> => {
const barContainer = barContainerEl?.value?.getBoundingClientRect()
if (!barContainer) {
return {}
}
// The bar either ends at the end of the container (overflow) or at the element's position in the chart
const barVisibleRight = Math.min(xEnd.value, barContainer.right - barContainer.left)
// The bar either starts at the beginning of the container (overflow) or at the element's position in the chart
const barVisibleLeft = Math.max(xStart.value, 0)
// Visible width of the bar
const barVisibleWidth = barVisibleRight - barVisibleLeft

// The label container is positioned from the left.
// If overflowing on the left, adjust the label's positioning to fit in the visible part
let offsetLeft = 0
if (xStart.value < 0) {
// Shift the left position by the width of the hidden part
offsetLeft = -xStart.value
}

return {
left: `${offsetLeft}px`,
width: `${barVisibleWidth}px`,
position: "absolute"
}
})

onMounted(() => {
watch(
[bar, width, chartStart, chartEnd, chartSize.width],
Expand Down
18 changes: 13 additions & 5 deletions src/components/GGanttBarTooltip.vue
Original file line number Diff line number Diff line change
Expand Up @@ -12,19 +12,20 @@
>
<div class="g-gantt-tooltip-color-dot" :style="{ background: dotColor }" />
<slot :bar="bar" :bar-start="barStartRaw" :bar-end="barEndRaw">
{{ tooltipContent }}
<span v-html="tooltipContent"></span>
</slot>
</div>
</transition>
</teleport>
</template>

<script setup lang="ts">
import { computed, toRefs, ref, watch, nextTick } from "vue"
import { computed, toRefs, ref, watch, nextTick, inject } from "vue"

import type { GanttBarObject } from "../types"
import useDayjsHelper from "../composables/useDayjsHelper.js"
import provideConfig from "../provider/provideConfig.js"
import { CHART_CONTAINER_KEY } from "../provider/symbols"

const TOOLTIP_FORMATS = {
hour: "HH:mm",
Expand All @@ -39,11 +40,14 @@ const DEFAULT_DOT_COLOR = "cadetblue"
const props = defineProps<{
bar: GanttBarObject | undefined
modelValue: boolean
tooltipTitle?: boolean
}>()

const { bar } = toRefs(props)
const { precision, font, barStart, barEnd, rowHeight } = provideConfig()

const barContainerEl = inject(CHART_CONTAINER_KEY)

const tooltipTop = ref("0px")
const tooltipLeft = ref("0px")
watch(
Expand All @@ -52,7 +56,7 @@ watch(
await nextTick()

const barId = bar?.value?.ganttBarConfig.id || ""
if (!barId) {
if (!barId || !barContainerEl?.value) {
return
}

Expand All @@ -61,7 +65,7 @@ watch(
top: 0,
left: 0
}
const leftValue = Math.max(left, 10)
const leftValue = Math.max(left, barContainerEl?.value.getBoundingClientRect().left)
tooltipTop.value = `${top + rowHeight.value - 10}px`
tooltipLeft.value = `${leftValue}px`
},
Expand All @@ -82,7 +86,11 @@ const tooltipContent = computed(() => {
const format = TOOLTIP_FORMATS[precision.value]
const barStartFormatted = toDayjs(barStartRaw.value).format(format)
const barEndFormatted = toDayjs(barEndRaw.value).format(format)
return `${barStartFormatted} \u2013 ${barEndFormatted}`
const title = props.tooltipTitle ? `${props?.bar?.ganttBarConfig.label} <br />` : ""
const subtitle = props?.bar?.ganttBarConfig.subtitle
? `<br />${props.bar.ganttBarConfig.subtitle}`
: ""
return `${title}${barStartFormatted} \u2013 ${barEndFormatted}${subtitle}`
})
</script>

Expand Down
28 changes: 26 additions & 2 deletions src/components/GGanttChart.vue
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,11 @@
</div>
</div>
</div>
<g-gantt-bar-tooltip :model-value="showTooltip || isDragging" :bar="tooltipBar">
<g-gantt-bar-tooltip
:model-value="showTooltip || isDragging"
:bar="tooltipBar"
:tooltipTitle="showLabelAsTooltipTitle"
>
<template #default>
<slot name="bar-tooltip" :bar="tooltipBar" />
</template>
Expand Down Expand Up @@ -77,6 +81,7 @@ import {
CHART_ROWS_KEY,
CONFIG_KEY,
EMIT_BAR_EVENT_KEY,
CHART_CONTAINER_KEY,
type ChartRow
} from "../provider/symbols.js"

Expand All @@ -97,9 +102,18 @@ export interface GGanttChartProps {
noOverlap?: boolean
rowHeight?: number
highlightedUnits?: number[]
highlightedDates?: number[]
highlightedDaysOfWeek?: number[]
highlightedHours?: number[]
font?: string
labelColumnTitle?: string
labelColumnWidth?: string
showDayName?: boolean
dayNameLength?: "short" | "long"
locale?: string
allowRightClickDragging?: boolean
disableDragging?: boolean
showLabelAsTooltipTitle?: boolean
}

export type GGanttChartConfig = ToRefs<Required<GGanttChartProps>> & {
Expand All @@ -122,9 +136,18 @@ const props = withDefaults(defineProps<GGanttChartProps>(), {
noOverlap: false,
rowHeight: 40,
highlightedUnits: () => [],
highlightedDates: () => [],
highlightedDaysOfWeek: () => [],
highlightedHours: () => [],
font: "inherit",
labelColumnTitle: "",
labelColumnWidth: "150px"
labelColumnWidth: "150px",
showDayName: true,
dayNameLength: "short",
locale: "en-GB",
allowRightClickDragging: false,
disableDragging: false,
showLabelAsTooltipTitle: true
})

const emit = defineEmits<{
Expand Down Expand Up @@ -254,6 +277,7 @@ const emitBarEvent = (
const ganttChart = ref<HTMLElement | null>(null)
const chartSize = useElementSize(ganttChart)

provide(CHART_CONTAINER_KEY, ganttChart)
provide(CHART_ROWS_KEY, getChartRows)
provide(CONFIG_KEY, {
...toRefs(props),
Expand Down
Loading