Skip to content

Commit

Permalink
Merge branch 'feature/group-connections' into develop
Browse files Browse the repository at this point in the history
  • Loading branch information
Xeyos88 committed Jan 25, 2025
2 parents 0fd9eec + ba335fb commit fbe6e0d
Show file tree
Hide file tree
Showing 6 changed files with 102 additions and 18 deletions.
2 changes: 0 additions & 2 deletions docs/guide/chart-configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ The GGanttChart component accepts several key configuration properties that defi
:bar-start="'start'"
:bar-end="'end'"
:row-height="40"
:width="'100%'"
:color-scheme="'default'"
:grid="true"
:push-on-overlap="true"
Expand All @@ -29,7 +28,6 @@ The GGanttChart component accepts several key configuration properties that defi
- `precision`: Sets the time unit ('hour', 'day', 'week', 'month')
- `bar-start` and `bar-end`: Specify data properties for dates
- `row-height`: Controls row height in pixels
- `width`: Chart width (percentage or pixels)

### Advanced Configuration

Expand Down
10 changes: 8 additions & 2 deletions src/components/GGanttRow.vue
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { FontAwesomeIcon } from "@fortawesome/vue-fontawesome"
import { faChevronRight, faChevronDown } from "@fortawesome/free-solid-svg-icons"
import useTimePositionMapping from "../composables/useTimePositionMapping"
import provideConfig from "../provider/provideConfig"
import type { GanttBarObject } from "../types"
import type { GanttBarConnection, GanttBarObject } from "../types"
import GGanttBar from "./GGanttBar.vue"
import { BAR_CONTAINER_KEY } from "../provider/symbols"
import type { UseRowsReturn } from "../composables/useRows"
Expand All @@ -20,7 +20,13 @@ const props = defineProps<{
bars: GanttBarObject[]
highlightOnHover?: boolean
id?: string | number
children?: { id: string | number; label: string; bars: GanttBarObject[] }[]
children?: {
id: string | number
label: string
bars: GanttBarObject[]
connections?: GanttBarConnection[]
}[]
connections?: GanttBarConnection[]
}>()
const emit = defineEmits<{
Expand Down
23 changes: 19 additions & 4 deletions src/composables/useBarDragManagement.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,12 +38,30 @@ const useBarDragManagement = () => {
isDragging: false
}

const getBundleBars = (bundle?: string) => {
const res: GanttBarObject[] = []
if (bundle != null) {
const allBars = movement.getAllBars()
allBars.forEach((bar) => {
if (bar.ganttBarConfig.bundle === bundle) {
res.push(bar)
}
})
}
return res
}

/**
* Initializes drag operation for a single bar
* @param bar - Bar to initialize drag for
* @param e - Mouse event that triggered the drag
*/
const initDragOfBar = (bar: GanttBarObject, e: MouseEvent) => {
if (bar.ganttBarConfig.bundle) {
initDragOfBundle(bar, e)
return
}

const dragHandler = createDragHandler(bar)
dragHandler.initiateDrag(e)
addBarToMovedBars(bar)
Expand All @@ -60,10 +78,7 @@ const useBarDragManagement = () => {
const bundle = mainBar.ganttBarConfig.bundle
if (!bundle) return

const bundleBars = rowManager.rows.value
.flatMap((row) => row.bars)
.filter((bar) => bar.ganttBarConfig.bundle === bundle)

const bundleBars = getBundleBars(bundle)
bundleBars.forEach((bar) => {
const isMainBar = bar === mainBar
const dragHandler = createDragHandler(bar, isMainBar)
Expand Down
73 changes: 67 additions & 6 deletions src/composables/useBarMovement.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ export interface MovementAPI {
moveBar: (bar: GanttBarObject, newStart: string, newEnd: string) => MovementResult
findOverlappingBars: (bar: GanttBarObject) => GanttBarObject[]
findConnectedBars: (bar: GanttBarObject) => GanttBarObject[]
getAllBars: () => GanttBarObject[]
}

/**
Expand Down Expand Up @@ -75,6 +76,24 @@ export function useBarMovement(
return endDate.isSameOrBefore(milestoneDate)
}

/**
* Gets all bars from all rows including nested groups
* @returns Array of all bars in the chart
*/
const getAllBars = (): GanttBarObject[] => {
const extractBarsFromRow = (row: any): GanttBarObject[] => {
let bars: GanttBarObject[] = [...row.bars]
if (row.children?.length) {
row.children.forEach((child: any) => {
bars = [...bars, ...extractBarsFromRow(child)]
})
}
return bars
}

return rowManager.rows.value.flatMap((row) => extractBarsFromRow(row))
}

/**
* Moves a bar to new start and end positions
* Handles validation and affected bar movement
Expand Down Expand Up @@ -107,6 +126,34 @@ export function useBarMovement(
bar[barStart.value] = newStart
bar[barEnd.value] = newEnd

if (bar.ganttBarConfig.bundle && initialMove) {
const bundleBars = getAllBars().filter(
(b) => b.ganttBarConfig.bundle === bar.ganttBarConfig.bundle && b !== bar
)

const timeDiff = dayjsHelper
.toDayjs(newStart)
.diff(dayjsHelper.toDayjs(originalStart), "minutes")

for (const bundleBar of bundleBars) {
const bundleBarNewStart = formatDate(
dayjsHelper.toDayjs(bundleBar[barStart.value]).add(timeDiff, "minutes")
)
const bundleBarNewEnd = formatDate(
dayjsHelper.toDayjs(bundleBar[barEnd.value]).add(timeDiff, "minutes")
)

const bundleResult = moveBar(bundleBar, bundleBarNewStart, bundleBarNewEnd, false)
if (!bundleResult.success) {
bar[barStart.value] = originalStart
bar[barEnd.value] = originalEnd
processedBars.delete(bar.ganttBarConfig.id)
return { success: false, affectedBars: new Set() }
}
bundleResult.affectedBars.forEach((b) => affectedBars.add(b))
}
}

const result = handleBarInteractions(bar, affectedBars)

if (!result.success) {
Expand All @@ -120,6 +167,7 @@ export function useBarMovement(
processedBars.clear()
}

affectedBars.add(bar)
return { success: true, affectedBars }
}

Expand Down Expand Up @@ -221,11 +269,23 @@ export function useBarMovement(
* @returns Array of overlapping bars
*/
const findOverlappingBars = (bar: GanttBarObject): GanttBarObject[] => {
const currentRow = rowManager.rows.value.find((row) => row.bars.includes(bar))
if (!currentRow) return []
const findRowForBar = (searchBar: GanttBarObject, rows: any[]): any | null => {
for (const row of rows) {
if (row.bars.includes(searchBar)) return row
if (row.children?.length) {
const foundInChildren = findRowForBar(searchBar, row.children)
if (foundInChildren) return foundInChildren
}
}
return null
}

const barRow = findRowForBar(bar, rowManager.rows.value)
if (!barRow) return []

return currentRow.bars.filter((otherBar) => {
return barRow.bars.filter((otherBar: GanttBarObject) => {
if (otherBar === bar || otherBar.ganttBarConfig.pushOnOverlap === false) return false
if (otherBar.ganttBarConfig.id.startsWith("group-")) return false

const start1 = dayjsHelper.toDayjs(bar[barStart.value])
const end1 = dayjsHelper.toDayjs(bar[barEnd.value])
Expand All @@ -245,7 +305,7 @@ export function useBarMovement(
* @returns Array of connected bars
*/
const findConnectedBars = (bar: GanttBarObject): GanttBarObject[] => {
const allBars = rowManager.rows.value.flatMap((row) => row.bars)
const allBars = getAllBars()
const connectedBars: GanttBarObject[] = []

bar.ganttBarConfig.connections?.forEach((conn) => {
Expand All @@ -266,12 +326,13 @@ export function useBarMovement(
})
})

return connectedBars
return connectedBars.filter((b) => !b.ganttBarConfig.id.startsWith("group-"))
}

return {
moveBar,
findOverlappingBars,
findConnectedBars
findConnectedBars,
getAllBars
}
}
9 changes: 6 additions & 3 deletions src/composables/useRows.ts
Original file line number Diff line number Diff line change
Expand Up @@ -83,24 +83,26 @@ export function useRows(

defaultSlot.forEach((child) => {
if (child.props?.bars || child.props?.children) {
const { label, bars = [], children = [], id } = child.props
const { label, bars = [], children = [], id, connections = [] } = child.props
rows.push({
id,
label,
bars,
children,
connections,
_originalNode: child
})
} else if (Array.isArray(child.children)) {
child.children.forEach((grandchild) => {
const grandchildNode = grandchild as { props?: ChartRow }
if (grandchildNode?.props?.bars || grandchildNode?.props?.children) {
const { label, bars = [], children = [], id } = grandchildNode.props
const { label, bars = [], children = [], id, connections = [] } = grandchildNode.props
rows.push({
id,
label,
bars,
children,
connections,
_originalNode: grandchildNode
})
}
Expand Down Expand Up @@ -173,7 +175,8 @@ export function useRows(
label: row.label,
style: {
background: "transparent"
}
},
connections: row.connections || []
}
}
]
Expand Down
3 changes: 2 additions & 1 deletion src/types/chart.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
import type { GanttBarObject } from "./bar"
import type { GanttBarConnection, GanttBarObject } from "./bar"

export interface ChartRow {
id?: string | number
label: string
bars: GanttBarObject[]
children?: ChartRow[]
connections?: GanttBarConnection[]
_originalNode?: any
}

Expand Down

0 comments on commit fbe6e0d

Please sign in to comment.