2
0
mirror of https://github.com/tenrok/vue-ganttastic.git synced 2026-06-25 13:50:33 +03:00

refactor: remove hardcode format and unit of time

This commit is contained in:
yicone
2021-02-02 15:54:56 +08:00
parent 0b79d21097
commit ac56ec12d7
4 changed files with 686 additions and 514 deletions
+179 -95
View File
@@ -12,11 +12,8 @@
@contextmenu="onContextmenu($event)"
>
<div class="g-gantt-bar-label">
<slot
name="bar-label"
:bar="bar"
>
{{barConfig.label || ""}}
<slot name="bar-label" :bar="bar">
{{ barConfig.label || '' }}
</slot>
</div>
<template v-if="barConfig.handles">
@@ -33,14 +30,16 @@
>
<div
class="color-indicator"
:style="{background: this.barStyle.background || this.barStyle.backgroundColor}"
:style="{
background:
this.barStyle.background || this.barStyle.backgroundColor,
}"
/>
{{bar[barStart] | TimeFilter}}
{{ bar[barStart] }}
-
{{bar[barEnd] | TimeFilter}}
{{ bar[barEnd] }}
</div>
</transition>
</div>
</template>
@@ -48,25 +47,27 @@
import moment from 'moment'
export default {
name: "GGanttBar",
name: 'GGanttBar',
props: {
bar: { type: Object },
barStart: { type: String }, // property name of the bar objects that represents the start datetime
barEnd: { type: String }, // property name of the bar objects that represents the end datetime,
barContainer: [Object, DOMRect],
allBarsInRow: {type: Array}
allBarsInRow: { type: Array },
},
inject: [
"getHourCount",
"ganttChartProps",
"initDragOfBarsFromBundle",
"moveBarsFromBundleOfPushedBar",
"setDragLimitsOfGanttBar",
"onBarEvent",
"onDragendBar",
"getMinGapBetweenBars",
'getTimeCount',
'ganttChartProps',
'initDragOfBarsFromBundle',
'moveBarsFromBundleOfPushedBar',
'setDragLimitsOfGanttBar',
'onBarEvent',
'onDragendBar',
'getMinGapBetweenBars',
'getTimeUnit',
'getTimeFormat',
],
data() {
@@ -83,6 +84,9 @@ export default {
// possible values: drag, dragByHandleLeft, dragByHandleRight,
barStartBeforeDrag: null,
barEndBeforeDrag: null,
timeUnit: this.getTimeUnit(),
timeChildKey: this.getTimeUnit() === 'days' ? 'hours' : 'minutes',
timeFormat: this.getTimeFormat(),
}
},
@@ -94,8 +98,8 @@ export default {
return moment(this.bar[this.barStart])
},
set(value) {
this.bar[this.barStart] = moment(value).format("YYYY-MM-DD HH:mm:ss")
}
this.bar[this.barStart] = moment(value).format(this.timeFormat)
},
},
barEndMoment: {
@@ -103,16 +107,21 @@ export default {
return moment(this.bar[this.barEnd])
},
set(value) {
this.bar[this.barEnd] = moment(value).format("YYYY-MM-DD HH:mm:ss")
}
this.bar[this.barEnd] = moment(value).format(this.timeFormat)
},
},
barConfig() {
if (this.bar.ganttBarConfig) {
return {
...this.bar.ganttBarConfig,
background: this.bar.ganttBarConfig.isShadow ? "grey" : this.bar.ganttBarConfig.background || this.bar.ganttBarConfig.backgroundColor,
opacity: this.bar.ganttBarConfig.isShadow ? "0.3" : this.bar.ganttBarConfig.opacity
background: this.bar.ganttBarConfig.isShadow
? 'grey'
: this.bar.ganttBarConfig.background ||
this.bar.ganttBarConfig.backgroundColor,
opacity: this.bar.ganttBarConfig.isShadow
? '0.3'
: this.bar.ganttBarConfig.opacity,
}
}
return {}
@@ -126,7 +135,7 @@ export default {
left: `${xStart}px`,
width: `${xEnd - xStart}px`,
height: `${this.ganttChartProps.rowHeight - 6}px`,
zIndex: this.barConfig.zIndex || (this.isDragging ? 2 : 1)
zIndex: this.barConfig.zIndex || (this.isDragging ? 2 : 1),
}
},
@@ -143,16 +152,15 @@ export default {
chartEndMoment() {
return moment(this.ganttChartProps.chartEnd)
}
},
},
methods: {
onMouseenter(e) {
if (this.tooltipTimeout) {
clearTimeout(this.tooltipTimeout)
}
this.tooltipTimeout = setTimeout(() => this.showTooltip = true, 800)
this.tooltipTimeout = setTimeout(() => (this.showTooltip = true), 800)
this.onBarEvent({ event: e, type: e.type }, this)
},
@@ -163,17 +171,23 @@ export default {
},
onContextmenu(e) {
const time = this.mapPositionToTime(e.clientX - this.barContainer.left).format("YYYY-MM-DD HH:mm:ss")
const time = this.mapPositionToTime(
e.clientX - this.barContainer.left
).format(this.timeFormat)
this.onBarEvent({ event: e, type: e.type, time }, this)
},
onClick(e) {
const time = this.mapPositionToTime(e.clientX - this.barContainer.left).format("YYYY-MM-DD HH:mm:ss")
const time = this.mapPositionToTime(
e.clientX - this.barContainer.left
).format(this.timeFormat)
this.onBarEvent({ event: e, type: e.type, time }, this)
},
onDblclick(e) {
const time = this.mapPositionToTime(e.clientX - this.barContainer.left).format("YYYY-MM-DD HH:mm:ss")
const time = this.mapPositionToTime(
e.clientX - this.barContainer.left
).format(this.timeFormat)
this.onBarEvent({ event: e, type: e.type, time }, this)
},
@@ -185,14 +199,19 @@ export default {
if (!this.barConfig.immobile && !this.barConfig.isShadow) {
this.setDragLimitsOfGanttBar(this)
// initialize the dragging on next mousemove event:
window.addEventListener("mousemove", this.onFirstMousemove, {once: true})
window.addEventListener('mousemove', this.onFirstMousemove, {
once: true,
})
// if next mousemove happens after mouse up (if user just presses mouse button down, then up, without moving):
window.addEventListener("mouseup",
() => window.removeEventListener("mousemove", this.onFirstMousemove),
window.addEventListener(
'mouseup',
() => window.removeEventListener('mousemove', this.onFirstMousemove),
{ once: true }
)
}
const time = this.mapPositionToTime(e.clientX - this.barContainer.left).format("YYYY-MM-DD HH:mm:ss")
const time = this.mapPositionToTime(
e.clientX - this.barContainer.left
).format(this.timeFormat)
this.onBarEvent({ event: e, type: e.type, time }, this)
},
@@ -206,31 +225,33 @@ export default {
/* --------------------------------------------------------- */
/* ------------- METHODS FOR DRAGGING THE BAR -------------- */
/* --------------------------------------------------------- */
initDrag(e){ // "e" must be the mousedown event
initDrag(e) {
// "e" must be the mousedown event
this.isDragging = true
this.barStartBeforeDrag = this.bar[this.barStart]
this.barEndBeforeDrag = this.bar[this.barEnd]
let barX = this.$refs["g-gantt-bar"].getBoundingClientRect().left
let barX = this.$refs['g-gantt-bar'].getBoundingClientRect().left
this.cursorOffsetX = e.clientX - barX
let mousedownType = e.target.className
switch (mousedownType) {
case "g-gantt-bar-handle-left":
document.body.style.cursor = "w-resize"
case 'g-gantt-bar-handle-left':
document.body.style.cursor = 'w-resize'
this.mousemoveCallback = this.dragByHandleLeft
break
case "g-gantt-bar-handle-right":
document.body.style.cursor = "w-resize"
case 'g-gantt-bar-handle-right':
document.body.style.cursor = 'w-resize'
this.mousemoveCallback = this.dragByHandleRight
break
default: this.mousemoveCallback = this.drag
default:
this.mousemoveCallback = this.drag
}
window.addEventListener("mousemove", this.mousemoveCallback)
window.addEventListener("mouseup", this.endDrag)
window.addEventListener('mousemove', this.mousemoveCallback)
window.addEventListener('mouseup', this.endDrag)
},
drag(e) {
let barWidth = this.$refs["g-gantt-bar"].getBoundingClientRect().width
let newXStart = (e.clientX-this.barContainer.left) - this.cursorOffsetX
let barWidth = this.$refs['g-gantt-bar'].getBoundingClientRect().width
let newXStart = e.clientX - this.barContainer.left - this.cursorOffsetX
let newXEnd = newXStart + barWidth
if (this.isPosOutOfDragRange(newXStart, newXEnd)) {
return
@@ -238,13 +259,16 @@ export default {
this.barStartMoment = this.mapPositionToTime(newXStart)
this.barEndMoment = this.mapPositionToTime(newXEnd)
this.manageOverlapping()
this.onBarEvent({event: e, type: "drag"}, this)
this.onBarEvent({ event: e, type: 'drag' }, this)
},
dragByHandleLeft(e) {
let newXStart = e.clientX - this.barContainer.left
let newStartMoment = this.mapPositionToTime(newXStart)
if(newStartMoment.isSameOrAfter(this.barEndMoment) || this.isPosOutOfDragRange(newXStart, null)){
if (
newStartMoment.isSameOrAfter(this.barEndMoment) ||
this.isPosOutOfDragRange(newXStart, null)
) {
return
}
this.barStartMoment = newStartMoment
@@ -254,7 +278,10 @@ export default {
dragByHandleRight(e) {
let newXEnd = e.clientX - this.barContainer.left
let newEndMoment = this.mapPositionToTime(newXEnd)
if(newEndMoment.isSameOrBefore(this.barStartMoment) || this.isPosOutOfDragRange(null, newXEnd)){
if (
newEndMoment.isSameOrBefore(this.barStartMoment) ||
this.isPosOutOfDragRange(null, newXEnd)
) {
return
}
this.barEndMoment = newEndMoment
@@ -269,10 +296,18 @@ export default {
if (xStart && xStart < 0) {
return true
}
if(xStart && this.dragLimitLeft !== null && xStart < this.dragLimitLeft + this.getMinGapBetweenBars()){
if (
xStart &&
this.dragLimitLeft !== null &&
xStart < this.dragLimitLeft + this.getMinGapBetweenBars()
) {
return true
}
if(xEnd && this.dragLimitRight !== null && xEnd > this.dragLimitRight - this.getMinGapBetweenBars()){
if (
xEnd &&
this.dragLimitRight !== null &&
xEnd > this.dragLimitRight - this.getMinGapBetweenBars()
) {
return true
}
return false
@@ -282,9 +317,9 @@ export default {
this.isDragging = false
this.dragLimitLeft = null
this.dragLimitRight = null
document.body.style.cursor = "auto"
window.removeEventListener("mousemove", this.mousemoveCallback)
window.removeEventListener("mouseup", this.endDrag)
document.body.style.cursor = 'auto'
window.removeEventListener('mousemove', this.mousemoveCallback)
window.removeEventListener('mouseup', this.endDrag)
if (this.isMainBarOfDrag) {
this.onDragendBar(e, this)
this.isMainBarOfDrag = false
@@ -297,7 +332,10 @@ export default {
},
manageOverlapping() {
if(!this.ganttChartProps.pushOnOverlap || this.barConfig.pushOnOverlap === false){
if (
!this.ganttChartProps.pushOnOverlap ||
this.barConfig.pushOnOverlap === false
) {
return
}
let currentBar = this.bar
@@ -309,24 +347,44 @@ export default {
let overlapStartMoment = moment(overlapBar[this.barStart])
let overlapEndMoment = moment(overlapBar[this.barEnd])
switch (overlapType) {
case "left":
minuteDiff = overlapEndMoment.diff(currentStartMoment, "minutes", true) + this.getMinGapBetweenBars()
overlapBar[this.barEnd] = currentStartMoment.subtract(this.getMinGapBetweenBars(), "minutes", true).format("YYYY-MM-DD HH:mm:ss")
overlapBar[this.barStart] = overlapStartMoment.subtract(minuteDiff, "minutes", true).format("YYYY-MM-DD HH:mm:ss")
case 'left':
minuteDiff =
overlapEndMoment.diff(
currentStartMoment,
this.timeChildKey,
true
) + this.getMinGapBetweenBars()
overlapBar[this.barEnd] = currentStartMoment
.subtract(this.getMinGapBetweenBars(), this.timeChildKey, true)
.format(this.timeFormat)
overlapBar[this.barStart] = overlapStartMoment
.subtract(minuteDiff, this.timeChildKey, true)
.format(this.timeFormat)
break
case "right":
minuteDiff = currentEndMoment.diff(overlapStartMoment, "minutes", true) + this.getMinGapBetweenBars()
overlapBar[this.barStart] = currentEndMoment.add(this.getMinGapBetweenBars(), "minutes", true).format("YYYY-MM-DD HH:mm:ss")
overlapBar[this.barEnd] = overlapEndMoment.add(minuteDiff, "minutes", true).format("YYYY-MM-DD HH:mm:ss")
case 'right':
minuteDiff =
currentEndMoment.diff(
overlapStartMoment,
this.timeChildKey,
true
) + this.getMinGapBetweenBars()
overlapBar[this.barStart] = currentEndMoment
.add(this.getMinGapBetweenBars(), this.timeChildKey, true)
.format(this.timeFormat)
overlapBar[this.barEnd] = overlapEndMoment
.add(minuteDiff, this.timeChildKey, true)
.format(this.timeFormat)
break
default:
// eslint-disable-next-line
console.warn("One bar is inside of the other one! This should never occur while push-on-overlap is active!")
console.warn(
'One bar is inside of the other one! This should never occur while push-on-overlap is active!'
)
return
}
this.moveBarsFromBundleOfPushedBar(overlapBar, minuteDiff, overlapType)
currentBar = overlapBar;
({overlapBar, overlapType} = this.getOverlapBarAndType(overlapBar))
currentBar = overlapBar
;({ overlapBar, overlapType } = this.getOverlapBarAndType(overlapBar))
}
},
@@ -334,19 +392,29 @@ export default {
let barStartMoment = moment(bar[this.barStart])
let barEndMoment = moment(bar[this.barEnd])
let overlapLeft, overlapRight, overlapInBetween
let overlapBar = this.allBarsInRow.find(otherBar => {
if(otherBar === bar || otherBar.ganttBarConfig.pushOnOverlap === false){
let overlapBar = this.allBarsInRow.find((otherBar) => {
if (
otherBar === bar ||
otherBar.ganttBarConfig.pushOnOverlap === false
) {
return false
}
let otherBarStart = moment(otherBar[this.barStart])
let otherBarEnd = moment(otherBar[this.barEnd])
overlapLeft = barStartMoment.isBetween(otherBarStart, otherBarEnd)
overlapRight = barEndMoment.isBetween(otherBarStart, otherBarEnd)
overlapInBetween = otherBarStart.isBetween(barStartMoment, barEndMoment)
|| otherBarEnd.isBetween(barStartMoment, barEndMoment)
overlapInBetween =
otherBarStart.isBetween(barStartMoment, barEndMoment) ||
otherBarEnd.isBetween(barStartMoment, barEndMoment)
return overlapLeft || overlapRight || overlapInBetween
})
let overlapType = overlapLeft ? "left" : (overlapRight ? "right" : (overlapInBetween ? "between" : null))
let overlapType = overlapLeft
? 'left'
: overlapRight
? 'right'
: overlapInBetween
? 'between'
: null
return { overlapBar, overlapType }
},
@@ -354,17 +422,33 @@ export default {
// so that bars from its bundle also get pushed
moveBarByMinutesAndPush(minuteCount, direction) {
switch (direction) {
case "left":
this.barStartMoment = moment(this.barStartMoment).subtract(minuteCount, "minutes", true)
this.barEndMoment = moment(this.barEndMoment).subtract(minuteCount, "minutes", true)
case 'left':
this.barStartMoment = moment(this.barStartMoment).subtract(
minuteCount,
this.timeChildKey,
true
)
this.barEndMoment = moment(this.barEndMoment).subtract(
minuteCount,
this.timeChildKey,
true
)
break
case "right":
this.barStartMoment = moment(this.barStartMoment).add(minuteCount, "minutes", true)
this.barEndMoment = moment(this.barEndMoment).add(minuteCount, "minutes", true)
case 'right':
this.barStartMoment = moment(this.barStartMoment).add(
minuteCount,
this.timeChildKey,
true
)
this.barEndMoment = moment(this.barEndMoment).add(
minuteCount,
this.timeChildKey,
true
)
break
default:
// eslint-disable-next-line
console.warn("wrong direction in moveBarByMinutesAndPush")
console.warn('wrong direction in moveBarByMinutesAndPush')
return
}
this.manageOverlapping()
@@ -374,22 +458,20 @@ export default {
/* ------- MAPPING POSITION TO TIME (AND VICE VERSA) ------- */
/* --------------------------------------------------------- */
mapTimeToPosition(time) {
let hourDiffFromStart = moment(time).diff(this.chartStartMoment, "hour", true)
return (hourDiffFromStart / this.getHourCount()) * this.barContainer.width
let timeDiffFromStart = moment(time).diff(
this.chartStartMoment,
this.timeUnit,
true
)
return (timeDiffFromStart / this.getTimeCount()) * this.barContainer.width
},
mapPositionToTime(xPos) {
let hourDiffFromStart = (xPos/this.barContainer.width)*this.getHourCount()
return this.chartStartMoment.clone().add(hourDiffFromStart, "hours")
let timeDiffFromStart =
(xPos / this.barContainer.width) * this.getTimeCount()
return this.chartStartMoment.clone().add(timeDiffFromStart, this.timeUnit)
},
},
filters:{
TimeFilter(value){
return moment(value).format("HH:mm")
}
}
}
</script>
@@ -425,7 +507,8 @@ export default {
text-overflow: ellipsis;
}
.g-gantt-bar > .g-gantt-bar-handle-left, .g-gantt-bar > .g-gantt-bar-handle-right {
.g-gantt-bar > .g-gantt-bar-handle-left,
.g-gantt-bar > .g-gantt-bar-handle-right {
position: absolute;
width: 10px;
height: 100%;
@@ -452,7 +535,7 @@ export default {
background: black;
color: white;
z-index: 3;
font-size: 0.70em;
font-size: 0.7em;
padding: 3px;
border-radius: 3px;
transition: opacity 0.2s;
@@ -482,17 +565,18 @@ export default {
}
.fade-enter-active {
animation: fade-in .3s;
animation: fade-in 0.3s;
}
.fade-leave-active {
animation: fade-in .3s reverse;
animation: fade-in 0.3s reverse;
}
@keyframes fade-in {
from {
opacity: 0;
} to {
}
to {
opacity: 1;
}
}
+167 -88
View File
@@ -22,9 +22,9 @@
/>
<div id="g-gantt-rows-container">
<slot/> <!-- the g-gantt-row components go here -->
<slot />
<!-- the g-gantt-row components go here -->
</div>
</div>
</template>
@@ -37,64 +37,67 @@ import GGanttRow from './GGanttRow.vue'
import GGanttBar from './GGanttBar.vue'
export default {
name: "GGanttChart",
name: 'GGanttChart',
components: {
GGanttTimeaxis,
GGanttGrid
GGanttGrid,
},
props: {
chartStart: {type: String, default: moment().startOf("day").format("YYYY-MM-DD HH:mm:ss")},
chartEnd: {type: String, default: moment().startOf("day").add(12,"hours").format("YYYY-MM-DD HH:mm:ss")},
chartStart: { type: String },
chartEnd: { type: String },
hideTimeaxis: Boolean,
rowLabelWidth: {type: String, default: "10%"},
rowLabelWidth: { type: String, default: '10%' },
rowHeight: { type: Number, default: 40 },
locale: {type: String, default: "en"},
locale: { type: String, default: 'en' },
theme: { type: String },
grid: { type: Boolean },
highlightedHours: { type: Array, default: () => [] },
width: {type: String, default: "100%"}, // the total width of the entire ganttastic component in %
width: { type: String, default: '100%' }, // the total width of the entire ganttastic component in %
pushOnOverlap: { type: Boolean },
snapBackOnOverlap: { type: Boolean },
minGapBetweenBars: {
type: Number,
default: 0
default: 0,
},
defaultBarLength: { type: Number, default: 1 },
// ["month_days", "day_hours"]
timeaxisMode: {type: String, default: "month_days"}
timeaxisMode: { type: String, default: 'month_days' },
},
data() {
return {
timemarkerOffset: 0,
movedBarsInDrag: new Set()
movedBarsInDrag: new Set(),
timeUnit: this.timeaxisMode === 'month_days' ? 'days' : 'hours',
timeFormat:
this.timeaxisMode === 'month_days' ? 'YYYY-MM-DD' : 'YYYY-MM-DD HH:mm',
}
},
computed: {
hourCount(){
timeCount() {
let momentChartStart = moment(this.chartStart)
let momentChartEnd = moment(this.chartEnd)
return Math.floor(momentChartEnd.diff(momentChartStart, "hour", true))
return Math.floor(momentChartEnd.diff(momentChartStart, this.timeUnit, true))
},
themeColors() {
return GanttasticThemeColors[this.theme] || GanttasticThemeColors.default
},
},
methods: {
getGanttBarChildrenList() {
let ganttBarChildren = []
let ganttRowChildrenList = this.$children.filter(childComp => childComp.$options.name === GGanttRow.name)
ganttRowChildrenList.forEach(row => {
let ganttBarChildrenOfRow = row.$children.filter(childComp => childComp.$options.name === GGanttBar.name)
let ganttRowChildrenList = this.$children.filter(
(childComp) => childComp.$options.name === GGanttRow.name
)
ganttRowChildrenList.forEach((row) => {
let ganttBarChildrenOfRow = row.$children.filter(
(childComp) => childComp.$options.name === GGanttBar.name
)
ganttBarChildren.push(...ganttBarChildrenOfRow)
})
return ganttBarChildren
@@ -104,15 +107,23 @@ export default {
if (bundleId === undefined || bundleId === null) {
return []
}
return this.getGanttBarChildrenList().filter(ganttBarChild => ganttBarChild.barConfig.bundle === bundleId)
return this.getGanttBarChildrenList().filter(
(ganttBarChild) => ganttBarChild.barConfig.bundle === bundleId
)
},
initDragOfBarsFromBundle(gGanttBar, e) {
gGanttBar.initDrag(e)
this.movedBarsInDrag.add(gGanttBar.bar)
if(gGanttBar.barConfig.bundle !== null && gGanttBar.barConfig.bundle !== undefined){
this.getGanttBarChildrenList().forEach(ganttBarChild => {
if(ganttBarChild.barConfig.bundle === gGanttBar.barConfig.bundle && ganttBarChild !== gGanttBar){
if (
gGanttBar.barConfig.bundle !== null &&
gGanttBar.barConfig.bundle !== undefined
) {
this.getGanttBarChildrenList().forEach((ganttBarChild) => {
if (
ganttBarChild.barConfig.bundle === gGanttBar.barConfig.bundle &&
ganttBarChild !== gGanttBar
) {
ganttBarChild.initDrag(e)
this.movedBarsInDrag.add(ganttBarChild.bar)
}
@@ -126,8 +137,11 @@ export default {
if (bundleId === undefined || bundleId === null) {
return
}
this.getGanttBarChildrenList().forEach(ganttBarChild => {
if(ganttBarChild.barConfig.bundle === bundleId && ganttBarChild.bar !== pushedBar){
this.getGanttBarChildrenList().forEach((ganttBarChild) => {
if (
ganttBarChild.barConfig.bundle === bundleId &&
ganttBarChild.bar !== pushedBar
) {
ganttBarChild.moveBarByMinutesAndPush(minuteDiff, overlapType)
this.movedBarsInDrag.add(ganttBarChild.bar)
}
@@ -135,7 +149,10 @@ export default {
},
shouldSnapBackBar(ganttBar) {
if(this.snapBackOnOverlap && ganttBar.barConfig.pushOnOverlap !== false){
if (
this.snapBackOnOverlap &&
ganttBar.barConfig.pushOnOverlap !== false
) {
let { overlapBar } = ganttBar.getOverlapBarAndType(ganttBar.bar)
return !!overlapBar
}
@@ -144,9 +161,12 @@ export default {
snapBackBundleIfNeeded(ganttBar) {
let barsFromBundle = this.getBarsFromBundle(ganttBar.barConfig.bundle)
if(this.shouldSnapBackBar(ganttBar) || barsFromBundle.some(gBar => this.shouldSnapBackBar(gBar))){
if (
this.shouldSnapBackBar(ganttBar) ||
barsFromBundle.some((gBar) => this.shouldSnapBackBar(gBar))
) {
ganttBar.snapBack()
barsFromBundle.forEach(gBar => gBar.snapBack())
barsFromBundle.forEach((gBar) => gBar.snapBack())
return true
}
return false
@@ -160,7 +180,7 @@ export default {
let didSnapBack = this.snapBackBundleIfNeeded(ganttBar)
let movedBars = didSnapBack ? new Set() : this.movedBarsInDrag
this.movedBarsInDrag = new Set()
this.$emit("dragend-bar", {event: e, bar: ganttBar.bar, movedBars})
this.$emit('dragend-bar', { event: e, bar: ganttBar.bar, movedBars })
},
// ------------------------------------------------------------------------
@@ -174,33 +194,54 @@ export default {
if (!this.pushOnOverlap || bar.barConfig.pushOnOverlap === false) {
return
}
for(let side of ["left", "right"]){
let [totalGapDistance, bundleBarsOnPath] = this.countGapDistanceToNextImmobileBar(bar, null, side, false)
for (let side of ['left', 'right']) {
let [
totalGapDistance,
bundleBarsOnPath,
] = this.countGapDistanceToNextImmobileBar(bar, null, side, false)
for (let i = 0; i < bundleBarsOnPath.length; i++) {
let barFromBundle = bundleBarsOnPath[i].bar
let gapDist = bundleBarsOnPath[i].gapDistance
let otherBarsFromBundle = this.getBarsFromBundle(barFromBundle.barConfig.bundle).filter(otherBar => otherBar !== barFromBundle)
otherBarsFromBundle.forEach(otherBar => {
let [newGapDistance, newBundleBars] = this.countGapDistanceToNextImmobileBar(otherBar, gapDist, side)
if(newGapDistance !== null && (newGapDistance < totalGapDistance || !totalGapDistance)){
let otherBarsFromBundle = this.getBarsFromBundle(
barFromBundle.barConfig.bundle
).filter((otherBar) => otherBar !== barFromBundle)
otherBarsFromBundle.forEach((otherBar) => {
let [
newGapDistance,
newBundleBars,
] = this.countGapDistanceToNextImmobileBar(otherBar, gapDist, side)
if (
newGapDistance !== null &&
(newGapDistance < totalGapDistance || !totalGapDistance)
) {
totalGapDistance = newGapDistance
}
newBundleBars.forEach(newBundleBar => {
if(!bundleBarsOnPath.find(barAndGap => barAndGap.bar === newBundleBar.bar)){
newBundleBars.forEach((newBundleBar) => {
if (
!bundleBarsOnPath.find(
(barAndGap) => barAndGap.bar === newBundleBar.bar
)
) {
bundleBarsOnPath.push(newBundleBar)
}
})
})
}
if(totalGapDistance != null && side === "left"){
bar.dragLimitLeft = bar.$refs['g-gantt-bar'].offsetLeft - totalGapDistance
} else if(totalGapDistance != null && side === "right"){
bar.dragLimitRight = bar.$refs['g-gantt-bar'].offsetLeft+ bar.$refs['g-gantt-bar'].offsetWidth + totalGapDistance
if (totalGapDistance != null && side === 'left') {
bar.dragLimitLeft =
bar.$refs['g-gantt-bar'].offsetLeft - totalGapDistance
} else if (totalGapDistance != null && side === 'right') {
bar.dragLimitRight =
bar.$refs['g-gantt-bar'].offsetLeft +
bar.$refs['g-gantt-bar'].offsetWidth +
totalGapDistance
}
}
// all bars from the bundle of the clicked bar need to have the same drag limit:
let barsFromBundleOfClickedBar = this.getBarsFromBundle(bar.barConfig.bundle)
barsFromBundleOfClickedBar.forEach(barFromBundle => {
let barsFromBundleOfClickedBar = this.getBarsFromBundle(
bar.barConfig.bundle
)
barsFromBundleOfClickedBar.forEach((barFromBundle) => {
barFromBundle.dragLimitLeft = bar.dragLimitLeft
barFromBundle.dragLimitRight = bar.dragLimitRight
})
@@ -209,77 +250,110 @@ export default {
// returns the gap distance to the next immobile bar
// in the row where the given bar (parameter) is (added to gapDistanceSoFar)
// and a list of all bars on that path that belong to a bundle
countGapDistanceToNextImmobileBar(bar, gapDistanceSoFar, side="left", ignoreShadows = true){
let bundleBarsAndGapDist = bar.barConfig.bundle ? [{bar, gapDistance: gapDistanceSoFar}] : []
countGapDistanceToNextImmobileBar(
bar,
gapDistanceSoFar,
side = 'left',
ignoreShadows = true
) {
let bundleBarsAndGapDist = bar.barConfig.bundle
? [{ bar, gapDistance: gapDistanceSoFar }]
: []
let currentBar = bar
let nextBar = this.getNextGanttBar(currentBar, side)
// left side:
if(side === "left"){
if (side === 'left') {
while (nextBar) {
let nextBarOffsetRight = nextBar.$refs['g-gantt-bar'].offsetLeft + nextBar.$refs['g-gantt-bar'].offsetWidth
gapDistanceSoFar += currentBar.$refs['g-gantt-bar'].offsetLeft - nextBarOffsetRight
if(nextBar.barConfig.immobile || (nextBar.barConfig.isShadow && !ignoreShadows)){
let nextBarOffsetRight =
nextBar.$refs['g-gantt-bar'].offsetLeft +
nextBar.$refs['g-gantt-bar'].offsetWidth
gapDistanceSoFar +=
currentBar.$refs['g-gantt-bar'].offsetLeft - nextBarOffsetRight
if (
nextBar.barConfig.immobile ||
(nextBar.barConfig.isShadow && !ignoreShadows)
) {
return [gapDistanceSoFar, bundleBarsAndGapDist]
} else if (nextBar.barConfig.bundle) {
bundleBarsAndGapDist.push({bar: nextBar, gapDistance: gapDistanceSoFar})
bundleBarsAndGapDist.push({
bar: nextBar,
gapDistance: gapDistanceSoFar,
})
}
currentBar = nextBar
nextBar = this.getNextGanttBar(nextBar, "left")
nextBar = this.getNextGanttBar(nextBar, 'left')
}
}
if(side === "right"){
if (side === 'right') {
while (nextBar) {
let currentBarOffsetRight = currentBar.$refs['g-gantt-bar'].offsetLeft + currentBar.$refs['g-gantt-bar'].offsetWidth
gapDistanceSoFar += nextBar.$refs['g-gantt-bar'].offsetLeft - currentBarOffsetRight
if(nextBar.barConfig.immobile || (nextBar.barConfig.isShadow && !ignoreShadows)){
let currentBarOffsetRight =
currentBar.$refs['g-gantt-bar'].offsetLeft +
currentBar.$refs['g-gantt-bar'].offsetWidth
gapDistanceSoFar +=
nextBar.$refs['g-gantt-bar'].offsetLeft - currentBarOffsetRight
if (
nextBar.barConfig.immobile ||
(nextBar.barConfig.isShadow && !ignoreShadows)
) {
return [gapDistanceSoFar, bundleBarsAndGapDist]
} else if (nextBar.barConfig.bundle) {
bundleBarsAndGapDist.push({bar: nextBar, gapDistance: gapDistanceSoFar})
bundleBarsAndGapDist.push({
bar: nextBar,
gapDistance: gapDistanceSoFar,
})
}
currentBar = nextBar
nextBar = this.getNextGanttBar(nextBar, "right")
nextBar = this.getNextGanttBar(nextBar, 'right')
}
}
return [null, bundleBarsAndGapDist]
},
getNextGanttBar(bar, side="left"){
getNextGanttBar(bar, side = 'left') {
let allBarsLeftOrRight = []
if(side === "left"){
allBarsLeftOrRight = bar.$parent.$children.filter(gBar => {
return gBar.$options.name === GGanttBar.name
&& gBar.$parent === bar.$parent
&& gBar.$refs['g-gantt-bar']
&& gBar.$refs['g-gantt-bar'].offsetLeft < bar.$refs['g-gantt-bar'].offsetLeft
&& gBar.barConfig.pushOnOverlap !== false
if (side === 'left') {
allBarsLeftOrRight = bar.$parent.$children.filter((gBar) => {
return (
gBar.$options.name === GGanttBar.name &&
gBar.$parent === bar.$parent &&
gBar.$refs['g-gantt-bar'] &&
gBar.$refs['g-gantt-bar'].offsetLeft <
bar.$refs['g-gantt-bar'].offsetLeft &&
gBar.barConfig.pushOnOverlap !== false
)
})
} else {
allBarsLeftOrRight = bar.$parent.$children.filter(gBar => {
return gBar.$options.name === GGanttBar.name
&& gBar.$parent === bar.$parent
&& gBar.$refs['g-gantt-bar']
&& gBar.$refs['g-gantt-bar'].offsetLeft > bar.$refs['g-gantt-bar'].offsetLeft
&& gBar.barConfig.pushOnOverlap !== false
allBarsLeftOrRight = bar.$parent.$children.filter((gBar) => {
return (
gBar.$options.name === GGanttBar.name &&
gBar.$parent === bar.$parent &&
gBar.$refs['g-gantt-bar'] &&
gBar.$refs['g-gantt-bar'].offsetLeft >
bar.$refs['g-gantt-bar'].offsetLeft &&
gBar.barConfig.pushOnOverlap !== false
)
})
}
if (allBarsLeftOrRight.length > 0) {
return allBarsLeftOrRight.reduce(
(bar1, bar2) => {
let bar1Dist = Math.abs(bar1.$refs['g-gantt-bar'].offsetLeft - bar.$refs['g-gantt-bar'].offsetLeft)
let bar2Dist = Math.abs(bar2.$refs['g-gantt-bar'].offsetLeft - bar.$refs['g-gantt-bar'].offsetLeft)
return bar1Dist < bar2Dist ? bar1 : bar2
},
allBarsLeftOrRight[0]
return allBarsLeftOrRight.reduce((bar1, bar2) => {
let bar1Dist = Math.abs(
bar1.$refs['g-gantt-bar'].offsetLeft -
bar.$refs['g-gantt-bar'].offsetLeft
)
let bar2Dist = Math.abs(
bar2.$refs['g-gantt-bar'].offsetLeft -
bar.$refs['g-gantt-bar'].offsetLeft
)
return bar1Dist < bar2Dist ? bar1 : bar2
}, allBarsLeftOrRight[0])
} else {
return null
}
}
},
// ------------------------------------------------------------------------
// ------------------------------------------------------------------------
// ------------------------------------------------------------------------
},
// all child components of GGanttChart may have access to
@@ -288,21 +362,26 @@ export default {
return {
getChartStart: () => this.chartStart,
getChartEnd: () => this.chartEnd,
getHourCount: () => this.hourCount,
getTimeCount: () => this.timeCount,
ganttChartProps: this.$props,
getThemeColors: () => this.themeColors,
initDragOfBarsFromBundle: (bundleId, e) => this.initDragOfBarsFromBundle(bundleId, e),
moveBarsFromBundleOfPushedBar: (bar, minuteDiff, overlapType) => this.moveBarsFromBundleOfPushedBar(bar, minuteDiff, overlapType),
setDragLimitsOfGanttBar : (ganttBar) => this.setDragLimitsOfGanttBar(ganttBar),
initDragOfBarsFromBundle: (bundleId, e) =>
this.initDragOfBarsFromBundle(bundleId, e),
moveBarsFromBundleOfPushedBar: (bar, minuteDiff, overlapType) =>
this.moveBarsFromBundleOfPushedBar(bar, minuteDiff, overlapType),
setDragLimitsOfGanttBar: (ganttBar) =>
this.setDragLimitsOfGanttBar(ganttBar),
onBarEvent: (e, ganttBar) => this.onBarEvent(e, ganttBar),
onDragendBar: (e, ganttBar) => this.onDragendBar(e, ganttBar),
shouldSnapBackOnOverlap: () => this.snapBackOnOverlap,
snapBackBundle: (ganttBar) => this.snapBackBundle(ganttBar),
getMinGapBetweenBars: () => this.minGapBetweenBars,
getDefaultBarLength: () => this.defaultBarLength,
getTimeaxisMode:() => this.timeaxisMode
}
getTimeaxisMode: () => this.timeaxisMode,
getTimeUnit: () => this.timeUnit,
getTimeFormat: () => this.timeFormat
}
},
}
</script>
+54 -45
View File
@@ -5,10 +5,7 @@
:style="{ height: `${$parent.rowHeight}px` }"
v-on="$listeners"
>
<div
class="g-gantt-row-label"
:style="rowLabelStyle"
>
<div class="g-gantt-row-label" :style="rowLabelStyle">
<slot name="label">
{{ label }}
</slot>
@@ -35,10 +32,7 @@
:all-bars-in-row="bars"
>
<template #bar-label="{ bar }">
<slot
name="bar-label"
:bar="bar"
/>
<slot name="bar-label" :bar="bar" />
</template>
</g-gantt-bar>
</div>
@@ -50,15 +44,14 @@ import GGanttBar from './GGanttBar.vue'
import moment from 'moment'
export default {
name: "GGanttRow",
name: 'GGanttRow',
components: {
GGanttBar
GGanttBar,
},
props: {
label: {type: String, default: "Row"},
label: { type: String, default: 'Row' },
bars: { type: Array, default: () => [] },
barStart: { type: String, required: true }, // property name of the bar objects that represents the start datetime
barEnd: { type: String, required: true }, // property name of the bar objects that represents the end datetime,
@@ -66,28 +59,31 @@ export default {
},
inject: [
"ganttChartProps",
"getThemeColors",
"getHourCount",
"getChartStart",
"getChartEnd",
"getDefaultBarLength"
'ganttChartProps',
'getThemeColors',
'getTimeCount',
'getChartStart',
'getChartEnd',
'getDefaultBarLength',
'getTimeUnit',
'getTimeFormat',
],
data() {
return {
barContainer: {}
barContainer: {},
timeUnit: this.getTimeUnit(),
timeFormat: this.getTimeFormat(),
}
},
computed: {
rowLabelStyle() {
return {
width: this.ganttChartProps.rowLabelWidth,
height: this.ganttChartProps.rowHeight,
background: this.$parent.themeColors.ternary,
color: this.$parent.themeColors.text
color: this.$parent.themeColors.text,
}
},
@@ -96,72 +92,86 @@ export default {
width: `${100 - this.ganttChartProps.rowLabelWidth.replace('%', '')}%`,
}
},
},
mounted() {
this.barContainer = this.$refs.barContainer.getBoundingClientRect()
window.addEventListener("resize", this.onWindowResize)
window.addEventListener('resize', this.onWindowResize)
},
methods: {
onDragover(e) {
e.preventDefault() // enables dropping content on row
if (this.highlightOnHover) {
console.log({backgroundColor: this.$refs["g-gantt-row"].style.backgroundColor })
this.$refs["g-gantt-row"].style.backgroundColor = this.getThemeColors().hoverHighlight
console.log({backgroundColor: this.$refs["g-gantt-row"].style.backgroundColor })
console.log({
backgroundColor: this.$refs['g-gantt-row'].style.backgroundColor,
})
this.$refs[
'g-gantt-row'
].style.backgroundColor = this.getThemeColors().hoverHighlight
console.log({
backgroundColor: this.$refs['g-gantt-row'].style.backgroundColor,
})
}
},
onDragleave() {
this.$refs["g-gantt-row"].style.backgroundColor = null
this.$refs['g-gantt-row'].style.backgroundColor = null
},
onDrop(e) {
let barContainer = this.$refs.barContainer.getBoundingClientRect()
let xPos = e.clientX - barContainer.left
let hourDiffFromStart = (xPos/barContainer.width) * this.getHourCount()
let time = moment(this.getChartStart()).add(hourDiffFromStart, "hours")
let bar = this.bars.find(bar => time.isBetween(bar[this.barStart], bar[this.barEnd]))
this.$emit("drop", {event: e, bar, time: time.format("YYYY-MM-DD HH:mm:ss")})
let timeDiffFromStart = (xPos / barContainer.width) * this.getTimeCount()
let time = moment(this.getChartStart()).add(
timeDiffFromStart,
this.timeUnit
)
let bar = this.bars.find((bar) =>
time.isBetween(bar[this.barStart], bar[this.barEnd])
)
this.$emit('drop', { event: e, bar, time: time.format(this.timeFormat) })
},
onDoubleClick(e) {
let barContainer = this.$refs.barContainer.getBoundingClientRect()
let xPos = e.clientX - barContainer.left
let hourDiffFromStart = (xPos/barContainer.width) * this.getHourCount()
let time = moment(this.getChartStart()).add(hourDiffFromStart, "hours")
let bar = {};
bar[this.barStart] = time.format("YYYY-MM-DD HH:mm:ss")
bar[this.barEnd] = time.add(this.getDefaultBarLength(), "hours").format("YYYY-MM-DD HH:mm:ss")
let timeDiffFromStart = (xPos / barContainer.width) * this.getTimeCount()
let time = moment(this.getChartStart()).add(
timeDiffFromStart,
this.timeUnit
)
let bar = {}
bar[this.barStart] = time
bar[this.barEnd] = time.add(this.getDefaultBarLength(), this.timeUnit)
bar.ganttBarConfig = { handles: true }
this.bars.push(bar)
},
onMouseover() {
if (this.highlightOnHover) {
this.$refs["g-gantt-row"].style.backgroundColor = this.getThemeColors().hoverHighlight
this.$refs[
'g-gantt-row'
].style.backgroundColor = this.getThemeColors().hoverHighlight
}
},
onMouseleave() {
this.$refs["g-gantt-row"].style.backgroundColor = null
this.$refs['g-gantt-row'].style.backgroundColor = null
},
onWindowResize() {
// re-initialize the barContainer DOMRect variable, which will trigger re-rendering in the gantt bars
this.barContainer = this.$refs.barContainer.getBoundingClientRect()
}
},
},
watch: {
'ganttChartProps.rowLabelWidth': function () {
this.barContainer = this.$refs.barContainer.getBoundingClientRect()
}
}
},
},
}
</script>
@@ -178,7 +188,7 @@ export default {
justify-content: center;
align-items: center;
width: 20%;
background: #E8E8E8;
background: #e8e8e8;
color: #424242;
font-size: 0.9em;
z-index: 3;
@@ -192,5 +202,4 @@ export default {
width: 70%;
border-bottom: 1px solid #eaeaea;
}
</style>
+7 -7
View File
@@ -55,7 +55,7 @@ import moment from 'moment'
export default {
name: 'GGanttTimeaxis',
inject: ['getTimeaxisMode'],
inject: ['getTimeaxisMode', 'getTimeUnit', 'getTimeFormat'],
props: {
chartStart: String,
@@ -74,6 +74,8 @@ export default {
hourFontSize: '11px',
dayFormat: 'MM-DD', // ISO 8601
mode: this.getTimeaxisMode(),
timeUnit: this.getTimeUnit(),
timeFormat: this.getTimeFormat()
}
},
@@ -100,8 +102,7 @@ export default {
let end = moment(this.chartEnd)
this.childPointCount = Math.floor(end.diff(start, 'day', true))
while (start.isBefore(end)) {
let dayCountOfMonth =
start.isSame(end, 'day')
let dayCountOfMonth = start.isSame(end, 'month')
? end.date()
: start.daysInMonth() - start.date() + 1
let widthPercentage = (dayCountOfMonth / this.childPointCount) * 100
@@ -119,8 +120,7 @@ export default {
let end = moment(this.chartEnd)
this.childPointCount = Math.floor(end.diff(start, 'hour', true))
while (start.isBefore(end)) {
let hourCountOfDay =
start.isSame(end, 'day')
let hourCountOfDay = start.isSame(end, 'day')
? end.hour()
: 24 - start.hour()
@@ -144,7 +144,7 @@ export default {
for (let i = 0; i <= endDay - startDay; i++) {
let day = {
text: datetimeMoment.format('D'),
fullDatetime: datetimeMoment.format('YYYY-MM-DD'), // ISO 8601
fullDatetime: datetimeMoment.format(this.timeFormat),
}
axisMonthObject.ganttDays.push(day)
datetimeMoment.add(1, 'day')
@@ -163,7 +163,7 @@ export default {
for (let i = 0; i <= endHour - startHour; i++) {
let hour = {
text: datetimeMoment.format('HH'),
fullDatetime: datetimeMoment.format('YYYY-MM-DD HH:mm'), // ISO 8601
fullDatetime: datetimeMoment.format(this.timeFormat),
}
axisDayObject.ganttHours.push(hour)
datetimeMoment.add(1, 'hour')