/**
* jQuery Gantt Chart
*
* @see http://taitems.github.io/jQuery.Gantt/
* @license MIT
*/
/*jshint camelcase:true, freeze:true, jquery:true */
;(function($, undefined) {
'use strict'
var UTC_DAY_IN_MS = 24 * 60 * 60 * 1000
var total = 0
// 计划年份
var planYear
// 记录原始top值
var curItemId = null
var historyTop = null
var hiddenBar = []
var isHidden = true
// custom selector `:findday` used to match on specified day in ms.
//
// The selector is passed a date in ms and elements are added to the
// selection filter if the element date matches, as determined by the
// id attribute containing a parsable date in ms.
// 打开链接方法
function openProjectUrl(url) {
if (url) {
window.oepn(url)
} else {
alert(123)
}
}
function findDay(elt, text) {
var cd = new Date(parseInt(text, 10))
cd.setHours(0, 0, 0, 0)
var id = $(elt).attr('id') || ''
var si = id.indexOf('-') + 1
var ed = new Date(parseInt(id.substring(si, id.length), 10))
ed.setHours(0, 0, 0, 0)
return cd.getTime() === ed.getTime()
}
$.expr.pseudos.findday = !$.expr.createPseudo
? function(elt, i, match) {
return findDay(elt, match[3])
}
: $.expr.createPseudo(function(text) {
return function(elt) {
return findDay(elt, text)
}
})
// custom selector `:findweek` used to match on specified week in ms.
function findWeek(elt, text) {
var cd = new Date(parseInt(text, 10))
var y = cd.getFullYear()
var w = cd.getWeekOfYear()
var m = cd.getMonth()
if (m === 11 && w === 1) {
y++
} else if (!m && w > 51) {
y--
}
cd = y + '-' + w
var id = $(elt).attr('id') || ''
var si = id.indexOf('-') + 1
var ed = id.substring(si, id.length)
return cd === ed
}
$.expr.pseudos.findweek = $.expr.createPseudo
? $.expr.createPseudo(function(text) {
return function(elt) {
return findWeek(elt, text)
}
})
: function(elt, i, match) {
return findWeek(elt, match[3])
}
// custom selector `:findmonth` used to match on specified month in ms.
function findMonth(elt, text) {
var cd = new Date(parseInt(text, 10))
cd = cd.getFullYear() + '-' + cd.getMonth()
var id = $(elt).attr('id') || ''
var si = id.indexOf('-') + 1
var ed = id.substring(si, id.length)
return cd === ed
}
$.expr[':'].findmonth = $.expr.createPseudo
? $.expr.createPseudo(function(text) {
return function(elt) {
return findMonth(elt, text)
}
})
: function(elt, i, match) {
return findMonth(elt, match[3])
}
// Date prototype helpers
// ======================
// `getWeekId` returns a string in the form of 'dh-YYYY-WW', where WW is
// the week # for the year.
// It is used to add an id to the week divs
Date.prototype.getWeekId = function() {
var y = this.getFullYear()
var w = this.getWeekOfYear()
var m = this.getMonth()
if (m === 11 && w === 1) {
y++
} else if (!m && w > 51) {
y--
}
return 'dh-' + y + '-' + w
}
// `getRepDate` returns the milliseconds since the epoch for a given date
// depending on the active scale
Date.prototype.getRepDate = function(scale) {
switch (scale) {
case 'hours':
return this.getTime()
case 'weeks':
return this.getDayForWeek().getTime()
case 'months':
return new Date(this.getFullYear(), this.getMonth(), 1).getTime()
case 'days':
/* falls through */
default:
return this.getTime()
}
}
// `getDayOfYear` returns the day number for the year
Date.prototype.getDayOfYear = function() {
var year = this.getFullYear()
return (Date.UTC(year, this.getMonth(), this.getDate()) - Date.UTC(year, 0, 0)) / UTC_DAY_IN_MS
}
// Use ISO week by default
//TODO: make these options.
var firstDay = 1 // ISO week starts with Monday (1); use Sunday (0) for, e.g., North America
var weekOneDate = 4 // ISO week one always contains 4 Jan; use 1 Jan for, e.g., North America
// `getWeekOfYear` returns the week number for the year
//TODO: fix bug when firstDay=6/weekOneDate=1 : https://github.com/moment/moment/issues/2115
Date.prototype.getWeekOfYear = function() {
var year = this.getFullYear(),
month = this.getMonth(),
date = this.getDate(),
day = this.getDay()
//var diff = weekOneDate - day + 7 * (day < firstDay ? -1 : 1);
var diff = weekOneDate - day
if (day < firstDay) {
diff -= 7
}
if (diff + 7 < weekOneDate - firstDay) {
diff += 7
}
return Math.ceil(new Date(year, month, date + diff).getDayOfYear() / 7)
}
// `getDayForWeek` returns the first day of this Date's week
Date.prototype.getDayForWeek = function() {
var day = this.getDay()
var diff = (day < firstDay ? -7 : 0) + firstDay - day
return new Date(this.getFullYear(), this.getMonth(), this.getDate() + diff)
}
// fixes https://github.com/taitems/jQuery.Gantt/issues/62
function ktkGetNextDate(currentDate, scaleStep) {
for (var minIncrements = 1; ; minIncrements++) {
var nextDate = new Date(currentDate)
nextDate.setHours(currentDate.getHours() + scaleStep * minIncrements)
if (nextDate.getTime() !== currentDate.getTime()) {
return nextDate
}
// If code reaches here, it's because current didn't really increment (invalid local time) because of daylight-saving adjustments
// => retry adding 2, 3, 4 hours, and so on (until nextDate > current)
}
}
$.fn.gantt = function(options) {
planYear = options.planYear
total = options.source.length
var scales = ['hours', 'days', 'weeks', 'months']
//Default settings
var settings = {
source: [],
holidays: [],
// paging
itemsPerPage: 7,
// localisation
dow: ['7', '1', '2', '3', '4', '5', '6'],
months: [
'一月',
'二月',
'三月',
'四月',
'五月',
'六月',
'七月',
'八月',
'九月',
'十月',
'十一月',
'十二月',
],
waitText: '加载中...',
// navigation
navigate: 'buttons',
scrollToToday: true,
// cookie options
useCookie: false,
cookieKey: 'jquery.fn.gantt',
// scale parameters
scale: 'days',
maxScale: 'months',
minScale: 'hours',
// callbacks
onItemClick: function(data) {
return
},
onAddClick: function(dt, rowId) {
return
},
onRender: $.noop,
}
// read options
$.extend(settings, options)
// can't use cookie if don't have `$.cookie`
settings.useCookie = settings.useCookie && $.isFunction($.cookie)
// Grid management
// ===============
// Core object is responsible for navigation and rendering
var core = {
// Return the element whose topmost point lies under the given point
// Normalizes for old browsers (NOTE: doesn't work when element is outside viewport)
//TODO: https://github.com/taitems/jQuery.Gantt/issues/137
elementFromPoint: (function() {
// IIFE
// version for normal browsers
if (document.compatMode === 'CSS1Compat') {
return function(x, y) {
x -= window.pageXOffset
y -= window.pageYOffset
return document.elementFromPoint(x, y)
}
}
// version for older browsers
return function(x, y) {
x -= $(document).scrollLeft()
y -= $(document).scrollTop()
return document.elementFromPoint(x, y)
}
})(),
// **Create the chart**
create: function(element) {
// Initialize data with a json object or fetch via an xhr
// request depending on `settings.source`
if (typeof settings.source !== 'string') {
element.data = settings.source
core.init(element)
} else {
$.getJSON(settings.source, function(jsData) {
element.data = jsData
core.init(element)
})
}
},
// **Setup the initial view**
// Here we calculate the number of rows, pages and visible start
// and end dates once the data are ready
init: function(element) {
element.rowsNum = element.data.length
element.pageCount = Math.ceil(element.rowsNum / settings.itemsPerPage)
element.rowsOnLastPage =
element.rowsNum -
Math.floor(element.rowsNum / settings.itemsPerPage) * settings.itemsPerPage
// element.dateStart = tools.getMinDate(element)
// element.dateEnd = tools.getMaxDate(element)
element.dateStart = new Date(planYear - 1 + '/10/1 00:00:00')
element.dateEnd = new Date(planYear + 1 + '/3/31 23:59:59')
/* core.render(element); */
core.waitToggle(element, function() {
core.render(element)
})
},
// **Render the grid**
render: function(element) {
var content = $('
')
var maindiv = $('')
var $leftPanel = core.leftPanel(element)
maindiv.append($leftPanel)
var $rightPanel = core.rightPanel(element, $leftPanel)
var pLeft, hPos
maindiv.append($rightPanel)
content.append(core.navigation(element))
var $dataPanel = $rightPanel.find('.dataPanel')
element.gantt = $('')
.append(maindiv)
.append(content)
$(element)
.empty()
.append(element.gantt)
element.scrollNavigation.panelMargin = parseInt(
$dataPanel.css('left').replace('px', ''),
10
)
element.scrollNavigation.panelMaxPos = $dataPanel.width() - $rightPanel.width()
element.scrollNavigation.canScroll = $dataPanel.width() > $rightPanel.width()
core.markNow(element)
core.fillData(element, $dataPanel, $leftPanel)
// Set a cookie to record current position in the view
if (settings.useCookie) {
var sc = $.cookie(settings.cookieKey + 'ScrollPos')
if (sc) {
element.hPosition = sc
}
}
// Scroll the grid to today's date
if (settings.scrollToToday) {
core.navigateTo(element, 'now')
core.scrollPanel(element, 0)
// or, scroll the grid to the left most date in the panel
} else {
if (element.hPosition !== 0) {
if (element.scaleOldWidth) {
pLeft = $dataPanel.width() - $rightPanel.width()
hPos = (pLeft * element.hPosition) / element.scaleOldWidth
element.hPosition = hPos > 0 ? 0 : hPos
element.scaleOldWidth = null
}
$dataPanel.css({ left: element.hPosition })
element.scrollNavigation.panelMargin = element.hPosition
}
core.repositionLabel(element)
}
$dataPanel.css({ height: $leftPanel.height() })
core.waitToggle(element)
settings.onRender()
},
// Create and return the left panel with labels
leftPanel: function(element) {
/* Left panel */
var ganttLeftPanel = $('').append(
$(
'
序号
项目名称
项目状态
'
).css('height', tools.getCellSize() * element.headerRows)
)
var entries = []
var k = 1
$.each(element.data, function(i, entry) {
if (
i >= element.pageNum * settings.itemsPerPage &&
i < element.pageNum * settings.itemsPerPage + settings.itemsPerPage
) {
var dataId = 'id' in entry ? '" data-id="' + entry.id : ''
entries.push(
'
'
)
}
}
})
return ganttLeftPanel.append(entries.join(''))
},
// Create and return the data panel element
dataPanel: function(element, width) {
var dataPanel = $('')
// Handle mousewheel events for scrolling the data panel
var wheel =
'onwheel' in element
? 'wheel'
: document.onmousewheel !== undefined
? 'mousewheel'
: 'DOMMouseScroll'
$(element).on(wheel, function(e) {
core.wheelScroll(element, e)
})
// Handle click events and dispatch to registered `onAddClick` function
dataPanel.click(function(e) {
e.stopPropagation()
var corrX /* <- never used? */, corrY
var leftpanel = $(element).find('.fn-gantt .leftPanel')
var datapanel = $(element).find('.fn-gantt .dataPanel')
switch (settings.scale) {
case 'months':
corrY = tools.getCellSize()
break
case 'hours':
corrY = tools.getCellSize() * 4
break
case 'days':
corrY = tools.getCellSize() * 3
break
case 'weeks':
/* falls through */
default:
corrY = tools.getCellSize() * 2
}
/* Adjust, so get middle of elm
corrY -= Math.floor(tools.getCellSize() / 2);
*/
// Find column where click occurred
var col = core.elementFromPoint(e.pageX, datapanel.offset().top + corrY)
// Was the label clicked directly?
if (col.className === 'fn-label') {
col = $(col.parentNode)
} else {
col = $(col)
}
var dt = col.data('repdate')
// Find row where click occurred
var row = core.elementFromPoint(leftpanel.offset().left + leftpanel.width() - 10, e.pageY)
// Was the label clicked directly?
if (row.className.indexOf('fn-label') === 0) {
row = $(row.parentNode)
} else {
row = $(row)
}
var rowId = row.data('id')
// Dispatch user registered function with the DateTime in ms
// and the id if the clicked object is a row
settings.onAddClick(dt, rowId)
})
return dataPanel
},
// Creates and return the right panel containing the year/week/day header
rightPanel: function(element, leftPanel /* <- never used? */) {
var range = null
// Days of the week have a class of one of
// `sn` (Sunday), `sa` (Saturday), or `wd` (Weekday)
var dowClass = ['sn', 'wd', 'wd', 'wd', 'wd', 'wd', 'sa']
//unused: was someone planning to allow styles to stretch to the bottom of the chart?
//var gridDowClass = [" sn", "", "", "", "", "", " sa"];
var yearArr = []
var scaleUnitsThisYear = 0
var monthArr = []
var scaleUnitsThisMonth = 0
var dayArr = []
var hoursInDay = 0
var dowArr = []
var horArr = []
var today = new Date()
today.setHours(0, 0, 0, 0)
// reused variables
var $row = $('')
var i, len
var year, month, week, day
var rday, dayClass
var dataPanel, dataPanelWidth
// Setup the headings based on the chosen `settings.scale`
switch (settings.scale) {
// **Hours**
case 'hours':
range = tools.parseTimeRange(element.dateStart, element.dateEnd, element.scaleStep)
dataPanelWidth = range.length * tools.getCellSize()
year = range[0].getFullYear()
month = range[0].getMonth()
day = range[0]
for (i = 0, len = range.length; i < len; i++) {
rday = range[i]
// Fill years
var rfy = rday.getFullYear()
if (rfy !== year) {
yearArr.push(
'
' +
year +
'
'
)
year = rfy
scaleUnitsThisYear = 0
}
scaleUnitsThisYear++
// Fill months
var rm = rday.getMonth()
if (rm !== month) {
monthArr.push(
'
' +
settings.months[month] +
'
'
)
month = rm
scaleUnitsThisMonth = 0
}
scaleUnitsThisMonth++
// Fill days & hours
var rgetDay = rday.getDay()
var getDay = day.getDay()
if (rgetDay !== getDay) {
dayClass =
today - day === 0
? 'today'
: tools.isHoliday(day.getTime())
? 'holiday'
: dowClass[getDay]
dayArr.push(
'
'
).data('dataObj', dataObj)
if (desc) {
bar
.mouseenter(function(e) {
if (itemId !== curItemId) {
//如过进入的不是当前组合,则直接展示新的
hiddenBar.map(function(bar, index) {
$(bar).css('top', historyTop)
})
hiddenBar = []
historyTop = null
}
isHidden = false
if (classNames != 'ganttRed' && historyTop == null) {
// 多个bar重叠时,将重叠的展示出来
var barList = document.querySelectorAll(
"[id='" +
itemId +
"'].ganttOne,[id='" +
itemId +
"'].ganttTwo,[id='" +
itemId +
"'].ganttThree"
)
var curBar = document.querySelector("[id='" + itemId + "']." + classNames)
barList.forEach(function(bar) {
if (
$(bar).css('left') == $(curBar).css('left') &&
$(bar)
.prop('className')
.indexOf(classNames) == -1
) {
hiddenBar.push(bar)
}
})
if (hiddenBar.length > 0) {
curItemId = itemId
historyTop = $(hiddenBar[0]).css('top')
hiddenBar.map(function(bar, index) {
$(bar).css(
'top',
parseFloat(historyTop.replace('px', '')) - (hiddenBar.length - index) * 15
)
})
}
}
var hint = $('').html(desc)
$('body').append(hint)
hint.css('left', e.pageX)
hint.css('top', e.pageY - 300)
hint.show()
})
.mouseleave(function() {
isHidden = true
setTimeout(function() {
if (isHidden) {
hiddenBar.map(function(bar, index) {
$(bar).css('top', historyTop)
})
hiddenBar = []
historyTop = null
}
}, 2000)
$('.fn-gantt-hint').remove()
})
.mousemove(function(e) {
$('.fn-gantt-hint').css('left', e.pageX)
$('.fn-gantt-hint').css('top', e.pageY + 15)
})
}
if (classNames) {
bar.addClass(classNames)
}
bar.click(function(e) {
e.stopPropagation()
settings.onItemClick($(this).data('dataObj'))
})
return bar
},
// Remove the `wd` (weekday) class and add `today` class to the
// current day/week/month (depending on the current scale)
markNow: function(element) {
var cd = new Date().setHours(0, 0, 0, 0)
switch (settings.scale) {
case 'weeks':
$(element)
.find(':findweek("' + cd + '")')
.removeClass('wd')
.addClass('today')
break
case 'months':
$(element)
.find(':findmonth("' + cd + '")')
.removeClass('wd')
.addClass('today')
break
case 'days':
/* falls through */
case 'hours':
/* falls through */
default:
$(element)
.find(':findday("' + cd + '")')
.removeClass('wd')
.addClass('today')
}
},
// **Fill the Chart**
// Parse the data and fill the data panel
fillData: function(element, datapanel, leftpanel /* <- never used? */) {
var cellWidth = tools.getCellSize()
var barOffset = (cellWidth - 18) / 2
var dataPanelWidth = datapanel.width()
var invertColor = function(colStr) {
try {
colStr = colStr.replace('rgb(', '').replace(')', '')
var rgbArr = colStr.split(',')
var R = parseInt(rgbArr[0], 10)
var G = parseInt(rgbArr[1], 10)
var B = parseInt(rgbArr[2], 10)
var gray = Math.round((255 - (0.299 * R + 0.587 * G + 0.114 * B)) * 0.9)
return 'rgb(' + gray + ', ' + gray + ', ' + gray + ')'
} catch (err) {
return ''
}
}
// Loop through the values of each data element and set a row
var indexNum = 0
$.each(element.data, function(i, entry) {
if (
i >= element.pageNum * settings.itemsPerPage &&
i < element.pageNum * settings.itemsPerPage + settings.itemsPerPage
) {
$.each(entry.values, function(j, day) {
var _bar
var from, to, cFrom, cTo, dFrom, dTo, dl, dp
var topEl, top
switch (settings.scale) {
// **Hourly data**
case 'hours':
dFrom = tools.genId(tools.dateDeserialize(day.from), element.scaleStep)
from = $(element).find('#dh-' + dFrom)
dTo = tools.genId(tools.dateDeserialize(day.to), element.scaleStep)
to = $(element).find('#dh-' + dTo)
cFrom = from.data('offset')
cTo = to.data('offset')
dl = Math.floor((cTo - cFrom) / cellWidth) + 1
dp = (100 * (cellWidth * dl - 1)) / dataPanelWidth
_bar = core.createProgressBar(
day.label,
day.desc,
day.customClass,
day.dataObj,
day.itemId
)
// find row
topEl = $(element).find('#rowheader' + i)
top = cellWidth * 5 + barOffset + topEl.data('offset')
_bar.css({
top: top,
left: Math.floor(cFrom),
width: dp + '%',
display: !cFrom && !cTo ? 'none' : '',
})
datapanel.append(_bar)
break
// **Weekly data**
case 'weeks':
dFrom = tools.dateDeserialize(day.from)
dTo = tools.dateDeserialize(day.to)
from = $(element).find('#' + dFrom.getWeekId())
cFrom = from.data('offset')
to = $(element).find('#' + dTo.getWeekId())
cTo = to.data('offset')
dl = Math.round((cTo - cFrom) / cellWidth) + 1
dp = (100 * (cellWidth * dl - 1)) / dataPanelWidth
// 如果没有开始或者结束,则不显示
if (!cTo | !cFrom) dp = 0
if (dp < 0) dp = 100
_bar = core.createProgressBar(
day.label,
day.desc,
day.customClass,
day.dataObj,
day.itemId
)
// find row
topEl = $(element).find('#rowheader' + i)
top = cellWidth * (3 + j) + barOffset + topEl.data('offset') + indexNum * 24
_bar.css({
top: top,
left: Math.floor(cFrom),
width: dp + '%',
display: !cFrom && !cTo ? 'none' : '',
})
datapanel.append(_bar)
break
// **Monthly data**
case 'months':
dFrom = tools.dateDeserialize(day.from)
dTo = tools.dateDeserialize(day.to)
if (dFrom.getDate() <= 3 && dFrom.getMonth() === 0) {
dFrom.setDate(dFrom.getDate() + 4)
}
if (dFrom.getDate() <= 3 && dFrom.getMonth() === 0) {
dFrom.setDate(dFrom.getDate() + 4)
}
if (dTo.getDate() <= 3 && dTo.getMonth() === 0) {
dTo.setDate(dTo.getDate() + 4)
}
from = $(element).find('#dh-' + tools.genId(dFrom))
cFrom = from.data('offset')
to = $(element).find('#dh-' + tools.genId(dTo))
cTo = to.data('offset')
dl = Math.round((cTo - cFrom) / cellWidth) + 1
dp = (100 * (cellWidth * dl - 1)) / dataPanelWidth
// 如果没有开始或者结束,则不显示
if (!cTo | !cFrom) dp = 0
if (dp < 0) dp = 100
_bar = core.createProgressBar(
day.label,
day.desc,
day.customClass,
day.dataObj,
day.itemId
)
// find row
topEl = $(element).find('#rowheader' + i)
top = cellWidth * (2 + j) + barOffset + topEl.data('offset') + indexNum * 24
_bar.css({
top: top,
left: Math.floor(cFrom) * 3,
width: dp * 3 + '%',
display: !cFrom && !cTo ? 'none' : '',
})
datapanel.append(_bar)
break
// **Days**
case 'days':
/* falls through */
default:
dFrom = tools.genId(tools.dateDeserialize(day.from))
dTo = tools.genId(tools.dateDeserialize(day.to))
from = $(element).find('#dh-' + dFrom)
cFrom = from.data('offset')
dl = Math.floor((dTo - dFrom) / UTC_DAY_IN_MS) + 1
dp = (100 * (cellWidth * dl - 1)) / dataPanelWidth
_bar = core.createProgressBar(
day.label,
day.desc,
day.customClass,
day.dataObj,
day.itemId
)
// find row
topEl = $(element).find('#rowheader' + i)
top = cellWidth * (4 + j) + barOffset + topEl.data('offset') + indexNum * 24
_bar.css({
top: top,
left: Math.floor(cFrom),
width: dp + '%',
display: !cFrom && !cTo ? 'none' : '',
})
datapanel.append(_bar)
}
var $l = _bar.find('.fn-label')
if ($l.length) {
var gray = invertColor(_bar.css('backgroundColor'))
$l.css('color', gray)
}
// if (j === 0) {
// indexNum++
// }
})
indexNum++
}
})
},
// **Navigation**
navigateTo: function(element, val) {
var $rightPanel = $(element).find('.fn-gantt .rightPanel')
var $dataPanel = $rightPanel.find('.dataPanel')
var rightPanelWidth = $rightPanel.width()
var dataPanelWidth = $dataPanel.width()
var shift = function() {
core.repositionLabel(element)
}
var maxLeft, curLeft
switch (val) {
case 'begin':
$dataPanel.animate({ left: '0' }, 'fast', shift)
element.scrollNavigation.panelMargin = 0
break
case 'end':
var pLeft = dataPanelWidth - rightPanelWidth
element.scrollNavigation.panelMargin = pLeft * -1
$dataPanel.animate({ left: '-' + pLeft }, 'fast', shift)
break
case 'now':
if (!element.scrollNavigation.canScroll || !$dataPanel.find('.today').length) {
return false
}
maxLeft = (dataPanelWidth - rightPanelWidth) * -1
curLeft = $dataPanel.css('left').replace('px', '')
val = $dataPanel.find('.today').offset().left - $dataPanel.offset().left
val *= -1
if (val > 0) {
val = 0
} else if (val < maxLeft) {
val = maxLeft
}
$dataPanel.animate({ left: val }, 'fast', shift)
element.scrollNavigation.panelMargin = val
break
default:
maxLeft = (dataPanelWidth - rightPanelWidth) * -1
curLeft = $dataPanel.css('left').replace('px', '')
val = parseInt(curLeft, 10) + val
if (val <= 0 && val >= maxLeft) {
$dataPanel.animate({ left: val }, 'fast', shift)
}
element.scrollNavigation.panelMargin = val
}
core.synchronizeScroller(element)
},
// Navigate to a specific page
navigatePage: function(element, val) {
if (
element.pageNum + val >= 0 &&
element.pageNum + val < Math.ceil(element.rowsNum / settings.itemsPerPage)
) {
core.waitToggle(element, function() {
element.pageNum += val
element.hPosition = $('.fn-gantt .dataPanel')
.css('left')
.replace('px', '')
element.scaleOldWidth = false
core.init(element)
})
}
},
// Change zoom level
zoomInOut: function(element, val) {
core.waitToggle(element, function() {
var scale = settings.scale
var headerRows = element.headerRows
var scaleSt = element.scaleStep
if (val == 1) {
scale = 'days'
headerRows = 4
scaleSt = 13
}
if (val == 2) {
scale = 'weeks'
headerRows = 3
scaleSt = 13
}
if (val == 3) {
scale = 'months'
headerRows = 2
scaleSt = 14
}
/* var zoomIn = (val < 0);
var scaleSt = element.scaleStep + val * 3;
scaleSt = scaleSt <= 1 ? 1 : scaleSt === 4 ? 3 : scaleSt;
var scale = settings.scale;
var headerRows = element.headerRows;
if (settings.scale === "hours" && scaleSt >= 13) {
scale = "days";
headerRows = 4;
scaleSt = 13;
} else if (settings.scale === "days" && zoomIn) {
scale = "hours";
headerRows = 5;
scaleSt = 12;
} else if (settings.scale === "days" && !zoomIn) {
scale = "weeks";
headerRows = 3;
scaleSt = 13;
} else if (settings.scale === "weeks" && !zoomIn) {
scale = "months";
headerRows = 2;
scaleSt = 14;
} else if (settings.scale === "weeks" && zoomIn) {
scale = "days";
headerRows = 4;
scaleSt = 13;
} else if (settings.scale === "months" && zoomIn) {
scale = "weeks";
headerRows = 3;
scaleSt = 13;
}
// do nothing if attempting to zoom past max/min
if ((zoomIn && $.inArray(scale, scales) < $.inArray(settings.minScale, scales)) ||
(!zoomIn && $.inArray(scale, scales) > $.inArray(settings.maxScale, scales))) {
core.init(element);
return;
}*/
element.scaleStep = scaleSt
settings.scale = scale
element.headerRows = headerRows
var $rightPanel = $(element).find('.fn-gantt .rightPanel')
var $dataPanel = $rightPanel.find('.dataPanel')
element.hPosition = $dataPanel.css('left').replace('px', '')
element.scaleOldWidth = $dataPanel.width() - $rightPanel.width()
if (settings.useCookie) {
$.cookie(settings.cookieKey + 'CurrentScale', settings.scale)
// reset scrollPos
$.cookie(settings.cookieKey + 'ScrollPos', null)
}
core.init(element)
})
},
// Move chart via mouseclick
mouseScroll: function(element, e) {
var $dataPanel = $(element).find('.fn-gantt .dataPanel')
$dataPanel.css('cursor', 'move')
var bPos = $dataPanel.offset()
var mPos =
element.scrollNavigation.mouseX === null ? e.pageX : element.scrollNavigation.mouseX
var delta = e.pageX - mPos
element.scrollNavigation.mouseX = e.pageX
core.scrollPanel(element, delta)
clearTimeout(element.scrollNavigation.repositionDelay)
element.scrollNavigation.repositionDelay = setTimeout(core.repositionLabel, 50, element)
},
// Move chart via mousewheel
wheelScroll: function(element, e) {
e.preventDefault() // e is a jQuery Event
// attempts to normalize scroll wheel velocity
var delta =
'detail' in e
? e.detail
: 'wheelDelta' in e.originalEvent
? (-1 / 120) * e.originalEvent.wheelDelta
: e.originalEvent.deltaY
? e.originalEvent.deltaY / Math.abs(e.originalEvent.deltaY)
: e.originalEvent.detail
// simpler normalization, ignoring per-device/browser/platform acceleration & semantic variations
//var delta = e.detail || - (e = e.originalEvent).wheelData || e.deltaY /* || e.deltaX */ || e.detail;
//delta = ( delta / Math.abs(delta) ) || 0;
core.scrollPanel(element, -50 * delta)
clearTimeout(element.scrollNavigation.repositionDelay)
element.scrollNavigation.repositionDelay = setTimeout(core.repositionLabel, 50, element)
},
// Move chart via slider control
sliderScroll: function(element, e) {
var $sliderBar = $(element).find('.nav-slider-bar')
var $sliderBarBtn = $sliderBar.find('.nav-slider-button')
var $rightPanel = $(element).find('.fn-gantt .rightPanel')
var $dataPanel = $rightPanel.find('.dataPanel')
var bPos = $sliderBar.offset()
var bWidth = $sliderBar.width()
var wButton = $sliderBarBtn.width()
var pos, pLeft
if (e.pageX >= bPos.left && e.pageX <= bPos.left + bWidth) {
pos = e.pageX - bPos.left
pos = pos - wButton / 2
$sliderBarBtn.css('left', pos)
pLeft = $dataPanel.width() - $rightPanel.width()
var pPos = ((pos * pLeft) / bWidth) * -1
if (pPos >= 0) {
$dataPanel.css('left', '0')
element.scrollNavigation.panelMargin = 0
} else if (pos >= bWidth - wButton * 1) {
$dataPanel.css('left', pLeft * -1)
element.scrollNavigation.panelMargin = pLeft * -1
} else {
$dataPanel.css('left', pPos)
element.scrollNavigation.panelMargin = pPos
}
clearTimeout(element.scrollNavigation.repositionDelay)
element.scrollNavigation.repositionDelay = setTimeout(core.repositionLabel, 5, element)
}
},
// Update scroll panel margins
scrollPanel: function(element, delta) {
if (!element.scrollNavigation.canScroll) {
return false
}
var _panelMargin = parseInt(element.scrollNavigation.panelMargin, 10) + delta
if (_panelMargin > 0) {
element.scrollNavigation.panelMargin = 0
$(element)
.find('.fn-gantt .dataPanel')
.css('left', element.scrollNavigation.panelMargin)
} else if (_panelMargin < element.scrollNavigation.panelMaxPos * -1) {
element.scrollNavigation.panelMargin = element.scrollNavigation.panelMaxPos * -1
$(element)
.find('.fn-gantt .dataPanel')
.css('left', element.scrollNavigation.panelMargin)
} else {
element.scrollNavigation.panelMargin = _panelMargin
$(element)
.find('.fn-gantt .dataPanel')
.css('left', element.scrollNavigation.panelMargin)
}
core.synchronizeScroller(element)
},
// Synchronize scroller
synchronizeScroller: function(element) {
if (settings.navigate !== 'scroll') {
return
}
var $rightPanel = $(element).find('.fn-gantt .rightPanel')
var $dataPanel = $rightPanel.find('.dataPanel')
var $sliderBar = $(element).find('.nav-slider-bar')
var $sliderBtn = $sliderBar.find('.nav-slider-button')
var bWidth = $sliderBar.width()
var wButton = $sliderBtn.width()
var pLeft = $dataPanel.width() - $rightPanel.width()
var hPos = $dataPanel.css('left') || 0
if (hPos) {
hPos = hPos.replace('px', '')
}
var pos = (hPos * bWidth) / pLeft - $sliderBtn.width() * 0.25
pos =
pos > 0 ? 0 : pos * -1 >= bWidth - wButton * 0.75 ? (bWidth - wButton * 1.25) * -1 : pos
$sliderBtn.css('left', pos * -1)
},
// Reposition data labels
repositionLabel: function(element) {
setTimeout(function() {
var $dataPanel
if (!element) {
$dataPanel = $('.fn-gantt .rightPanel .dataPanel')
} else {
var $rightPanel = $(element).find('.fn-gantt .rightPanel')
$dataPanel = $rightPanel.find('.dataPanel')
}
if (settings.useCookie) {
$.cookie(settings.cookieKey + 'ScrollPos', $dataPanel.css('left').replace('px', ''))
}
}, 500)
},
// waitToggle
waitToggle: function(element, showCallback) {
if ($.isFunction(showCallback)) {
var $elt = $(element)
var eo = $elt.offset()
var ew = $elt.outerWidth()
var eh = $elt.outerHeight()
if (!element.loader) {
element.loader = $(
'
' +
'
' +
settings.waitText +
'
'
)
}
$elt.append(element.loader)
setTimeout(showCallback, 500)
} else if (element.loader) {
element.loader.detach()
}
},
}
// Utility functions
// =================
var tools = {
// Return the maximum available date in data depending on the scale
getMaxDate: function(element) {
var maxDate = null
$.each(element.data, function(i, entry) {
$.each(entry.values, function(i, date) {
maxDate =
maxDate < tools.dateDeserialize(date.to) ? tools.dateDeserialize(date.to) : maxDate
})
})
maxDate = maxDate || new Date()
var bd
bd = new Date(maxDate.getTime())
maxDate = new Date(bd.getFullYear() + 1, 2, 31)
/*switch (settings.scale) {
case "hours":
maxDate.setHours(Math.ceil((maxDate.getHours()) / element.scaleStep) * element.scaleStep);
maxDate.setHours(maxDate.getHours() + element.scaleStep * 3);
break;
case "weeks":
// wtf is happening here?
bd = new Date(maxDate.getTime());
bd = new Date(bd.setDate(bd.getDate() + 3 * 7));
var md = Math.floor(bd.getDate() / 7) * 7;
maxDate = new Date(bd.getFullYear(), bd.getMonth(), md === 0 ? 4 : md - 3);
break;
case "months":
bd = new Date(maxDate.getFullYear(), maxDate.getMonth(), 1);
bd.setMonth(bd.getMonth() + 2);
maxDate = new Date(bd.getFullYear(), bd.getMonth(), 1);
break;
case "days":
falls through
default:
maxDate.setHours(0);
maxDate.setDate(maxDate.getDate() + 3);
}*/
return maxDate
},
// Return the minimum available date in data depending on the scale
getMinDate: function(element) {
var minDate = null
$.each(element.data, function(i, entry) {
$.each(entry.values, function(i, date) {
minDate =
minDate > tools.dateDeserialize(date.from) || minDate === null
? tools.dateDeserialize(date.from)
: minDate
})
})
minDate = minDate || new Date()
var bd = null
bd = new Date(minDate.getTime())
minDate = new Date(bd.getFullYear() - 1, 9, 1)
/* switch (settings.scale) {
case "hours":
minDate.setHours(Math.floor((minDate.getHours()) / element.scaleStep) * element.scaleStep);
minDate.setHours(minDate.getHours() - element.scaleStep * 3);
break;
case "weeks":
// wtf is happening here?
var bd = new Date(minDate.getTime());
bd = new Date(bd.setDate(bd.getDate() - 3 * 7));
var md = Math.floor(bd.getDate() / 7) * 7;
minDate = new Date(bd.getFullYear(), bd.getMonth(), md === 0 ? 4 : md - 3);
break;
case "months":
minDate.setHours(0, 0, 0, 0);
minDate.setDate(1);
minDate.setMonth(minDate.getMonth() - 3);
break;
case "days":
falls through
default:
minDate.setHours(0, 0, 0, 0);
minDate.setDate(minDate.getDate() - 3);
}*/
return minDate
},
// Return an array of Date objects between `from` and `to`
parseDateRange: function(from, to) {
var current = new Date(from.getTime())
var ret = []
var i = 0
do {
ret[i++] = new Date(current.getTime())
current.setDate(current.getDate() + 1)
} while (current <= to)
return ret
},
// Return an array of Date objects between `from` and `to`,
// scaled hourly
parseTimeRange: function(from, to, scaleStep) {
var current = new Date(from)
var end = new Date(to)
// GR: Fix begin
current.setHours(0, 0, 0, 0)
end.setMilliseconds(0)
end.setSeconds(0)
if (end.getMinutes() > 0 || end.getHours() > 0) {
end.setMinutes(0)
end.setHours(0)
end.setTime(end.getTime() + UTC_DAY_IN_MS)
}
// GR: Fix end
var ret = []
var i = 0
for (;;) {
var dayStartTime = new Date(current)
dayStartTime.setHours(Math.floor(current.getHours() / scaleStep) * scaleStep)
if (ret[i] && dayStartTime.getDay() !== ret[i].getDay()) {
// If mark-cursor jumped to next day, make sure it starts at 0 hours
dayStartTime.setHours(0)
}
ret[i] = dayStartTime
// Note that we use ">" because we want to include the end-time point.
if (current > to) {
break
}
/* BUG-2: current is moved backwards producing a dead-lock! (crashes chrome/IE/firefox)
* SEE: https://github.com/taitems/jQuery.Gantt/issues/62
if (current.getDay() !== ret[i].getDay()) {
current.setHours(0);
}
*/
// GR Fix Begin
current = ktkGetNextDate(dayStartTime, scaleStep)
// GR Fix End
i++
}
return ret
},
// Return an array of Date objects between a range of weeks
// between `from` and `to`
parseWeeksRange: function(from, to) {
var current = from.getDayForWeek()
var ret = []
var i = 0
do {
ret[i++] = current.getDayForWeek()
current.setDate(current.getDate() + 7)
} while (current <= to)
return ret
},
// Return an array of Date objects between a range of months
// between `from` and `to`
parseMonthsRange: function(from, to) {
var current = new Date(from)
var end = new Date(to) // <- never used?
var ret = []
var i = 0
do {
ret[i++] = new Date(current.getFullYear(), current.getMonth(), 1)
current.setMonth(current.getMonth() + 1)
} while (current <= to)
return ret
},
// Deserialize a date from a string or integer
dateDeserialize: function(date) {
if (typeof date === 'string') {
date = date.replace(/\/Date\((.*)\)\//, '$1')
date = $.isNumeric(date) ? parseInt(date, 10) : $.trim(date)
}
return new Date(date)
},
// Generate an id for a date
genId: function(t) {
// varargs
if ($.isNumeric(t)) {
t = new Date(t)
}
switch (settings.scale) {
case 'hours':
var hour = t.getHours()
if (arguments.length >= 2) {
hour = Math.floor(t.getHours() / arguments[1]) * arguments[1]
}
return new Date(t.getFullYear(), t.getMonth(), t.getDate(), hour).getTime()
case 'weeks':
var y = t.getFullYear()
var w = t.getWeekOfYear()
var m = t.getMonth()
if (m === 11 && w === 1) {
y++
} else if (!m && w > 51) {
y--
}
return y + '-' + w
case 'months':
return t.getFullYear() + '-' + t.getMonth()
case 'days':
/* falls through */
default:
return new Date(t.getFullYear(), t.getMonth(), t.getDate()).getTime()
}
},
// normalizes an array of dates into a map of start-of-day millisecond values
_datesToDays: function(dates) {
var dayMap = {}
for (var i = 0, len = dates.length, day; i < len; i++) {
day = tools.dateDeserialize(dates[i])
dayMap[day.setHours(0, 0, 0, 0)] = true
}
return dayMap
},
// Returns true when the given date appears in the array of holidays, if provided
isHoliday: (function() {
// IIFE
// short-circuits the function if no holidays option was passed
if (!settings.holidays || !settings.holidays.length) {
return function() {
return false
}
}
var holidays = false
// returns the function that will be used to check for holidayness of a given date
return function(date) {
if (!holidays) {
holidays = tools._datesToDays(settings.holidays)
}
return !!holidays[
// assumes numeric dates are already normalized to start-of-day
$.isNumeric(date)
? date
: new Date(date.getFullYear(), date.getMonth(), date.getDate()).getTime()
]
}
})(),
// Get the current cell height
getCellSize: function() {
if (typeof tools._getCellSize === 'undefined') {
var measure = $(
'
'
)
$('body').append(measure)
tools._getCellSize = measure.find('.row').height()
measure.empty().remove()
}
return tools._getCellSize
},
// Get the current page height
getPageHeight: function(element) {
return element.pageNum + 1 === element.pageCount
? element.rowsOnLastPage * tools.getCellSize()
: settings.itemsPerPage * tools.getCellSize()
},
}
this.each(function() {
this.data = null // Received data
this.pageNum = 0 // Current page number
this.pageCount = 0 // Available pages count
this.rowsOnLastPage = 0 // How many rows on last page
this.rowsNum = 0 // Number of total rows
this.hPosition = 0 // Current position on diagram (Horizontal)
this.dateStart = null
this.dateEnd = null
this.scrollClicked = false
this.scaleOldWidth = null
this.headerRows = null
// Update cookie with current scale
if (settings.useCookie) {
var sc = $.cookie(settings.cookieKey + 'CurrentScale')
if (sc) {
settings.scale = sc
} else {
$.cookie(settings.cookieKey + 'CurrentScale', settings.scale)
}
}
switch (settings.scale) {
//case "hours":
// this.headerRows = 5;
// this.scaleStep = 8;
// break;
case 'hours':
this.headerRows = 5
this.scaleStep = 1
break
case 'weeks':
this.headerRows = 3
this.scaleStep = 13
break
case 'months':
this.headerRows = 2
this.scaleStep = 14
break
case 'days':
/* falls through */
default:
this.headerRows = 4
this.scaleStep = 13
}
this.scrollNavigation = {
panelMouseDown: false,
scrollerMouseDown: false,
mouseX: null,
panelMargin: 0,
repositionDelay: 0,
panelMaxPos: 0,
canScroll: true,
}
this.gantt = null
this.loader = null
core.create(this)
})
}
})(jQuery)