jquery.fn.gantt.js 75 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166
  1. /**
  2. * jQuery Gantt Chart
  3. *
  4. * @see http://taitems.github.io/jQuery.Gantt/
  5. * @license MIT
  6. */
  7. /*jshint camelcase:true, freeze:true, jquery:true */
  8. ;(function($, undefined) {
  9. 'use strict'
  10. var UTC_DAY_IN_MS = 24 * 60 * 60 * 1000
  11. var total = 0
  12. // 计划年份
  13. var planYear
  14. // 记录原始top值
  15. var curItemId = null
  16. var historyTop = null
  17. var hiddenBar = []
  18. var isHidden = true
  19. // custom selector `:findday` used to match on specified day in ms.
  20. //
  21. // The selector is passed a date in ms and elements are added to the
  22. // selection filter if the element date matches, as determined by the
  23. // id attribute containing a parsable date in ms.
  24. // 打开链接方法
  25. function openProjectUrl(url) {
  26. if (url) {
  27. window.oepn(url)
  28. } else {
  29. alert(123)
  30. }
  31. }
  32. function findDay(elt, text) {
  33. var cd = new Date(parseInt(text, 10))
  34. cd.setHours(0, 0, 0, 0)
  35. var id = $(elt).attr('id') || ''
  36. var si = id.indexOf('-') + 1
  37. var ed = new Date(parseInt(id.substring(si, id.length), 10))
  38. ed.setHours(0, 0, 0, 0)
  39. return cd.getTime() === ed.getTime()
  40. }
  41. $.expr.pseudos.findday = !$.expr.createPseudo
  42. ? function(elt, i, match) {
  43. return findDay(elt, match[3])
  44. }
  45. : $.expr.createPseudo(function(text) {
  46. return function(elt) {
  47. return findDay(elt, text)
  48. }
  49. })
  50. // custom selector `:findweek` used to match on specified week in ms.
  51. function findWeek(elt, text) {
  52. var cd = new Date(parseInt(text, 10))
  53. var y = cd.getFullYear()
  54. var w = cd.getWeekOfYear()
  55. var m = cd.getMonth()
  56. if (m === 11 && w === 1) {
  57. y++
  58. } else if (!m && w > 51) {
  59. y--
  60. }
  61. cd = y + '-' + w
  62. var id = $(elt).attr('id') || ''
  63. var si = id.indexOf('-') + 1
  64. var ed = id.substring(si, id.length)
  65. return cd === ed
  66. }
  67. $.expr.pseudos.findweek = $.expr.createPseudo
  68. ? $.expr.createPseudo(function(text) {
  69. return function(elt) {
  70. return findWeek(elt, text)
  71. }
  72. })
  73. : function(elt, i, match) {
  74. return findWeek(elt, match[3])
  75. }
  76. // custom selector `:findmonth` used to match on specified month in ms.
  77. function findMonth(elt, text) {
  78. var cd = new Date(parseInt(text, 10))
  79. cd = cd.getFullYear() + '-' + cd.getMonth()
  80. var id = $(elt).attr('id') || ''
  81. var si = id.indexOf('-') + 1
  82. var ed = id.substring(si, id.length)
  83. return cd === ed
  84. }
  85. $.expr[':'].findmonth = $.expr.createPseudo
  86. ? $.expr.createPseudo(function(text) {
  87. return function(elt) {
  88. return findMonth(elt, text)
  89. }
  90. })
  91. : function(elt, i, match) {
  92. return findMonth(elt, match[3])
  93. }
  94. // Date prototype helpers
  95. // ======================
  96. // `getWeekId` returns a string in the form of 'dh-YYYY-WW', where WW is
  97. // the week # for the year.
  98. // It is used to add an id to the week divs
  99. Date.prototype.getWeekId = function() {
  100. var y = this.getFullYear()
  101. var w = this.getWeekOfYear()
  102. var m = this.getMonth()
  103. if (m === 11 && w === 1) {
  104. y++
  105. } else if (!m && w > 51) {
  106. y--
  107. }
  108. return 'dh-' + y + '-' + w
  109. }
  110. // `getRepDate` returns the milliseconds since the epoch for a given date
  111. // depending on the active scale
  112. Date.prototype.getRepDate = function(scale) {
  113. switch (scale) {
  114. case 'hours':
  115. return this.getTime()
  116. case 'weeks':
  117. return this.getDayForWeek().getTime()
  118. case 'months':
  119. return new Date(this.getFullYear(), this.getMonth(), 1).getTime()
  120. case 'days':
  121. /* falls through */
  122. default:
  123. return this.getTime()
  124. }
  125. }
  126. // `getDayOfYear` returns the day number for the year
  127. Date.prototype.getDayOfYear = function() {
  128. var year = this.getFullYear()
  129. return (Date.UTC(year, this.getMonth(), this.getDate()) - Date.UTC(year, 0, 0)) / UTC_DAY_IN_MS
  130. }
  131. // Use ISO week by default
  132. //TODO: make these options.
  133. var firstDay = 1 // ISO week starts with Monday (1); use Sunday (0) for, e.g., North America
  134. var weekOneDate = 4 // ISO week one always contains 4 Jan; use 1 Jan for, e.g., North America
  135. // `getWeekOfYear` returns the week number for the year
  136. //TODO: fix bug when firstDay=6/weekOneDate=1 : https://github.com/moment/moment/issues/2115
  137. Date.prototype.getWeekOfYear = function() {
  138. var year = this.getFullYear(),
  139. month = this.getMonth(),
  140. date = this.getDate(),
  141. day = this.getDay()
  142. //var diff = weekOneDate - day + 7 * (day < firstDay ? -1 : 1);
  143. var diff = weekOneDate - day
  144. if (day < firstDay) {
  145. diff -= 7
  146. }
  147. if (diff + 7 < weekOneDate - firstDay) {
  148. diff += 7
  149. }
  150. return Math.ceil(new Date(year, month, date + diff).getDayOfYear() / 7)
  151. }
  152. // `getDayForWeek` returns the first day of this Date's week
  153. Date.prototype.getDayForWeek = function() {
  154. var day = this.getDay()
  155. var diff = (day < firstDay ? -7 : 0) + firstDay - day
  156. return new Date(this.getFullYear(), this.getMonth(), this.getDate() + diff)
  157. }
  158. // fixes https://github.com/taitems/jQuery.Gantt/issues/62
  159. function ktkGetNextDate(currentDate, scaleStep) {
  160. for (var minIncrements = 1; ; minIncrements++) {
  161. var nextDate = new Date(currentDate)
  162. nextDate.setHours(currentDate.getHours() + scaleStep * minIncrements)
  163. if (nextDate.getTime() !== currentDate.getTime()) {
  164. return nextDate
  165. }
  166. // If code reaches here, it's because current didn't really increment (invalid local time) because of daylight-saving adjustments
  167. // => retry adding 2, 3, 4 hours, and so on (until nextDate > current)
  168. }
  169. }
  170. $.fn.gantt = function(options) {
  171. planYear = options.planYear
  172. total = options.source.length
  173. var scales = ['hours', 'days', 'weeks', 'months']
  174. //Default settings
  175. var settings = {
  176. source: [],
  177. holidays: [],
  178. // paging
  179. itemsPerPage: 7,
  180. // localisation
  181. dow: ['7', '1', '2', '3', '4', '5', '6'],
  182. months: [
  183. '一月',
  184. '二月',
  185. '三月',
  186. '四月',
  187. '五月',
  188. '六月',
  189. '七月',
  190. '八月',
  191. '九月',
  192. '十月',
  193. '十一月',
  194. '十二月',
  195. ],
  196. waitText: '加载中...',
  197. // navigation
  198. navigate: 'buttons',
  199. scrollToToday: true,
  200. // cookie options
  201. useCookie: false,
  202. cookieKey: 'jquery.fn.gantt',
  203. // scale parameters
  204. scale: 'days',
  205. maxScale: 'months',
  206. minScale: 'hours',
  207. // callbacks
  208. onItemClick: function(data) {
  209. return
  210. },
  211. onAddClick: function(dt, rowId) {
  212. return
  213. },
  214. onRender: $.noop,
  215. }
  216. // read options
  217. $.extend(settings, options)
  218. // can't use cookie if don't have `$.cookie`
  219. settings.useCookie = settings.useCookie && $.isFunction($.cookie)
  220. // Grid management
  221. // ===============
  222. // Core object is responsible for navigation and rendering
  223. var core = {
  224. // Return the element whose topmost point lies under the given point
  225. // Normalizes for old browsers (NOTE: doesn't work when element is outside viewport)
  226. //TODO: https://github.com/taitems/jQuery.Gantt/issues/137
  227. elementFromPoint: (function() {
  228. // IIFE
  229. // version for normal browsers
  230. if (document.compatMode === 'CSS1Compat') {
  231. return function(x, y) {
  232. x -= window.pageXOffset
  233. y -= window.pageYOffset
  234. return document.elementFromPoint(x, y)
  235. }
  236. }
  237. // version for older browsers
  238. return function(x, y) {
  239. x -= $(document).scrollLeft()
  240. y -= $(document).scrollTop()
  241. return document.elementFromPoint(x, y)
  242. }
  243. })(),
  244. // **Create the chart**
  245. create: function(element) {
  246. // Initialize data with a json object or fetch via an xhr
  247. // request depending on `settings.source`
  248. if (typeof settings.source !== 'string') {
  249. element.data = settings.source
  250. core.init(element)
  251. } else {
  252. $.getJSON(settings.source, function(jsData) {
  253. element.data = jsData
  254. core.init(element)
  255. })
  256. }
  257. },
  258. // **Setup the initial view**
  259. // Here we calculate the number of rows, pages and visible start
  260. // and end dates once the data are ready
  261. init: function(element) {
  262. element.rowsNum = element.data.length
  263. element.pageCount = Math.ceil(element.rowsNum / settings.itemsPerPage)
  264. element.rowsOnLastPage =
  265. element.rowsNum -
  266. Math.floor(element.rowsNum / settings.itemsPerPage) * settings.itemsPerPage
  267. // element.dateStart = tools.getMinDate(element)
  268. // element.dateEnd = tools.getMaxDate(element)
  269. element.dateStart = new Date(planYear - 1 + '/10/1 00:00:00')
  270. element.dateEnd = new Date(planYear + 1 + '/3/31 23:59:59')
  271. /* core.render(element); */
  272. core.waitToggle(element, function() {
  273. core.render(element)
  274. })
  275. },
  276. // **Render the grid**
  277. render: function(element) {
  278. var content = $('<div class="fn-content"/>')
  279. var maindiv = $('<div class="main-div-custom"></div>')
  280. var $leftPanel = core.leftPanel(element)
  281. maindiv.append($leftPanel)
  282. var $rightPanel = core.rightPanel(element, $leftPanel)
  283. var pLeft, hPos
  284. maindiv.append($rightPanel)
  285. content.append(core.navigation(element))
  286. var $dataPanel = $rightPanel.find('.dataPanel')
  287. element.gantt = $('<div class="fn-gantt" />')
  288. .append(maindiv)
  289. .append(content)
  290. $(element)
  291. .empty()
  292. .append(element.gantt)
  293. element.scrollNavigation.panelMargin = parseInt(
  294. $dataPanel.css('left').replace('px', ''),
  295. 10
  296. )
  297. element.scrollNavigation.panelMaxPos = $dataPanel.width() - $rightPanel.width()
  298. element.scrollNavigation.canScroll = $dataPanel.width() > $rightPanel.width()
  299. core.markNow(element)
  300. core.fillData(element, $dataPanel, $leftPanel)
  301. // Set a cookie to record current position in the view
  302. if (settings.useCookie) {
  303. var sc = $.cookie(settings.cookieKey + 'ScrollPos')
  304. if (sc) {
  305. element.hPosition = sc
  306. }
  307. }
  308. // Scroll the grid to today's date
  309. if (settings.scrollToToday) {
  310. core.navigateTo(element, 'now')
  311. core.scrollPanel(element, 0)
  312. // or, scroll the grid to the left most date in the panel
  313. } else {
  314. if (element.hPosition !== 0) {
  315. if (element.scaleOldWidth) {
  316. pLeft = $dataPanel.width() - $rightPanel.width()
  317. hPos = (pLeft * element.hPosition) / element.scaleOldWidth
  318. element.hPosition = hPos > 0 ? 0 : hPos
  319. element.scaleOldWidth = null
  320. }
  321. $dataPanel.css({ left: element.hPosition })
  322. element.scrollNavigation.panelMargin = element.hPosition
  323. }
  324. core.repositionLabel(element)
  325. }
  326. $dataPanel.css({ height: $leftPanel.height() })
  327. core.waitToggle(element)
  328. settings.onRender()
  329. },
  330. // Create and return the left panel with labels
  331. leftPanel: function(element) {
  332. /* Left panel */
  333. var ganttLeftPanel = $('<div class="leftPanel"/>').append(
  334. $(
  335. '<div class="row spacer"><div class="pindex" style="line-height:' +
  336. tools.getCellSize() * element.headerRows +
  337. 'px">序号</div><div class="pname" style="line-height:' +
  338. tools.getCellSize() * element.headerRows +
  339. 'px">项目名称</div><div class="pstatus" style="line-height:' +
  340. tools.getCellSize() * element.headerRows +
  341. 'px">项目状态</div></div>'
  342. ).css('height', tools.getCellSize() * element.headerRows)
  343. )
  344. var entries = []
  345. var k = 1
  346. $.each(element.data, function(i, entry) {
  347. if (
  348. i >= element.pageNum * settings.itemsPerPage &&
  349. i < element.pageNum * settings.itemsPerPage + settings.itemsPerPage
  350. ) {
  351. var dataId = 'id' in entry ? '" data-id="' + entry.id : ''
  352. entries.push(
  353. '<div class="row name row' +
  354. i +
  355. (entry.desc ? '' : ' fn-wide ' + dataId) +
  356. '" id="rowheader' +
  357. i +
  358. '" data-offset="' +
  359. (i % settings.itemsPerPage) * tools.getCellSize() +
  360. '" >' +
  361. '<span class="indexspan">' +
  362. (i + 1) +
  363. '</span><span class="fn-label' +
  364. (entry.cssClass ? ' ' + entry.cssClass : '') +
  365. '" title="' +
  366. (entry.name || '') +
  367. '">' +
  368. '<a rel="opener" target="_blank" href="' +
  369. entry.url +
  370. '" >' +
  371. (entry.name || '') +
  372. '</a>' +
  373. '</span>' +
  374. '</div>'
  375. )
  376. k++
  377. if (entry.desc) {
  378. entries.push(
  379. '<div class="row desc row' +
  380. i +
  381. ' " id="RowdId_' +
  382. i +
  383. dataId +
  384. '">' +
  385. '<span class="fn-label' +
  386. (entry.cssClass ? ' ' + entry.cssClass : '') +
  387. '">' +
  388. entry.desc +
  389. '</span>' +
  390. '</div>'
  391. )
  392. }
  393. }
  394. })
  395. return ganttLeftPanel.append(entries.join(''))
  396. },
  397. // Create and return the data panel element
  398. dataPanel: function(element, width) {
  399. var dataPanel = $('<div class="dataPanel" style="width: ' + width + 'px;"/>')
  400. // Handle mousewheel events for scrolling the data panel
  401. var wheel =
  402. 'onwheel' in element
  403. ? 'wheel'
  404. : document.onmousewheel !== undefined
  405. ? 'mousewheel'
  406. : 'DOMMouseScroll'
  407. $(element).on(wheel, function(e) {
  408. core.wheelScroll(element, e)
  409. })
  410. // Handle click events and dispatch to registered `onAddClick` function
  411. dataPanel.click(function(e) {
  412. e.stopPropagation()
  413. var corrX /* <- never used? */, corrY
  414. var leftpanel = $(element).find('.fn-gantt .leftPanel')
  415. var datapanel = $(element).find('.fn-gantt .dataPanel')
  416. switch (settings.scale) {
  417. case 'months':
  418. corrY = tools.getCellSize()
  419. break
  420. case 'hours':
  421. corrY = tools.getCellSize() * 4
  422. break
  423. case 'days':
  424. corrY = tools.getCellSize() * 3
  425. break
  426. case 'weeks':
  427. /* falls through */
  428. default:
  429. corrY = tools.getCellSize() * 2
  430. }
  431. /* Adjust, so get middle of elm
  432. corrY -= Math.floor(tools.getCellSize() / 2);
  433. */
  434. // Find column where click occurred
  435. var col = core.elementFromPoint(e.pageX, datapanel.offset().top + corrY)
  436. // Was the label clicked directly?
  437. if (col.className === 'fn-label') {
  438. col = $(col.parentNode)
  439. } else {
  440. col = $(col)
  441. }
  442. var dt = col.data('repdate')
  443. // Find row where click occurred
  444. var row = core.elementFromPoint(leftpanel.offset().left + leftpanel.width() - 10, e.pageY)
  445. // Was the label clicked directly?
  446. if (row.className.indexOf('fn-label') === 0) {
  447. row = $(row.parentNode)
  448. } else {
  449. row = $(row)
  450. }
  451. var rowId = row.data('id')
  452. // Dispatch user registered function with the DateTime in ms
  453. // and the id if the clicked object is a row
  454. settings.onAddClick(dt, rowId)
  455. })
  456. return dataPanel
  457. },
  458. // Creates and return the right panel containing the year/week/day header
  459. rightPanel: function(element, leftPanel /* <- never used? */) {
  460. var range = null
  461. // Days of the week have a class of one of
  462. // `sn` (Sunday), `sa` (Saturday), or `wd` (Weekday)
  463. var dowClass = ['sn', 'wd', 'wd', 'wd', 'wd', 'wd', 'sa']
  464. //unused: was someone planning to allow styles to stretch to the bottom of the chart?
  465. //var gridDowClass = [" sn", "", "", "", "", "", " sa"];
  466. var yearArr = []
  467. var scaleUnitsThisYear = 0
  468. var monthArr = []
  469. var scaleUnitsThisMonth = 0
  470. var dayArr = []
  471. var hoursInDay = 0
  472. var dowArr = []
  473. var horArr = []
  474. var today = new Date()
  475. today.setHours(0, 0, 0, 0)
  476. // reused variables
  477. var $row = $('<div class="row header"></div>')
  478. var i, len
  479. var year, month, week, day
  480. var rday, dayClass
  481. var dataPanel, dataPanelWidth
  482. // Setup the headings based on the chosen `settings.scale`
  483. switch (settings.scale) {
  484. // **Hours**
  485. case 'hours':
  486. range = tools.parseTimeRange(element.dateStart, element.dateEnd, element.scaleStep)
  487. dataPanelWidth = range.length * tools.getCellSize()
  488. year = range[0].getFullYear()
  489. month = range[0].getMonth()
  490. day = range[0]
  491. for (i = 0, len = range.length; i < len; i++) {
  492. rday = range[i]
  493. // Fill years
  494. var rfy = rday.getFullYear()
  495. if (rfy !== year) {
  496. yearArr.push(
  497. '<div class="row year" style="width: ' +
  498. tools.getCellSize() * scaleUnitsThisYear +
  499. 'px;"><div class="fn-label">' +
  500. year +
  501. '</div></div>'
  502. )
  503. year = rfy
  504. scaleUnitsThisYear = 0
  505. }
  506. scaleUnitsThisYear++
  507. // Fill months
  508. var rm = rday.getMonth()
  509. if (rm !== month) {
  510. monthArr.push(
  511. '<div class="row month" style="width: ' +
  512. tools.getCellSize() * scaleUnitsThisMonth +
  513. 'px"><div class="fn-label">' +
  514. settings.months[month] +
  515. '</div></div>'
  516. )
  517. month = rm
  518. scaleUnitsThisMonth = 0
  519. }
  520. scaleUnitsThisMonth++
  521. // Fill days & hours
  522. var rgetDay = rday.getDay()
  523. var getDay = day.getDay()
  524. if (rgetDay !== getDay) {
  525. dayClass =
  526. today - day === 0
  527. ? 'today'
  528. : tools.isHoliday(day.getTime())
  529. ? 'holiday'
  530. : dowClass[getDay]
  531. dayArr.push(
  532. '<div class="row date ' +
  533. dayClass +
  534. '" ' +
  535. 'style="width: ' +
  536. tools.getCellSize() * hoursInDay +
  537. 'px;">' +
  538. '<div class="fn-label">' +
  539. day.getDate() +
  540. '</div></div>'
  541. )
  542. dowArr.push(
  543. '<div class="row day ' +
  544. dayClass +
  545. '" ' +
  546. 'style="width: ' +
  547. tools.getCellSize() * hoursInDay +
  548. 'px;">' +
  549. '<div class="fn-label">' +
  550. settings.dow[getDay] +
  551. '</div></div>'
  552. )
  553. day = rday
  554. hoursInDay = 0
  555. }
  556. hoursInDay++
  557. dayClass = dowClass[rgetDay]
  558. if (tools.isHoliday(rday)) {
  559. dayClass = 'holiday'
  560. }
  561. horArr.push(
  562. '<div class="row day ' +
  563. dayClass +
  564. '" id="dh-' +
  565. rday.getTime() +
  566. '" data-offset="' +
  567. i * tools.getCellSize() +
  568. '" data-repdate="' +
  569. rday.getRepDate(settings.scale) +
  570. '"><div class="fn-label">' +
  571. rday.getHours() +
  572. '</div></div>'
  573. )
  574. }
  575. // Last year
  576. yearArr.push(
  577. '<div class="row year" style="width: ' +
  578. tools.getCellSize() * scaleUnitsThisYear +
  579. 'px;"><div class="fn-label">' +
  580. year +
  581. '</div></div>'
  582. )
  583. // Last month
  584. monthArr.push(
  585. '<div class="row month" style="width: ' +
  586. tools.getCellSize() * scaleUnitsThisMonth +
  587. 'px"><div class="fn-label">' +
  588. settings.months[month] +
  589. '</div></div>'
  590. )
  591. dayClass = dowClass[day.getDay()]
  592. if (tools.isHoliday(day)) {
  593. dayClass = 'holiday'
  594. }
  595. dayArr.push(
  596. '<div class="row date ' +
  597. dayClass +
  598. '" ' +
  599. 'style="width: ' +
  600. tools.getCellSize() * hoursInDay +
  601. 'px;">' +
  602. '<div class="fn-label">' +
  603. day.getDate() +
  604. '</div></div>'
  605. )
  606. dowArr.push(
  607. '<div class="row day ' +
  608. dayClass +
  609. '" ' +
  610. 'style="width: ' +
  611. tools.getCellSize() * hoursInDay +
  612. 'px;">' +
  613. '<div class="fn-label">' +
  614. settings.dow[day.getDay()] +
  615. '</div></div>'
  616. )
  617. dataPanel = core.dataPanel(element, dataPanelWidth)
  618. // Append panel elements
  619. dataPanel.append(
  620. $row.clone().html(yearArr.join('')),
  621. $row.clone().html(monthArr.join('')),
  622. $row.clone().html(dayArr.join('')),
  623. $row.clone().html(dowArr.join('')),
  624. $row.clone().html(horArr.join(''))
  625. )
  626. break
  627. // **Weeks**
  628. case 'weeks':
  629. range = tools.parseWeeksRange(element.dateStart, element.dateEnd)
  630. dataPanelWidth = range.length * tools.getCellSize()
  631. year = range[0].getFullYear()
  632. month = range[0].getMonth()
  633. week = range[0].getWeekOfYear()
  634. var diff
  635. for (i = 0, len = range.length; i < len; i++) {
  636. rday = range[i]
  637. // Fill years
  638. if (week > (week = rday.getWeekOfYear())) {
  639. // partial weeks to subtract from year header
  640. diff = rday.getDate() - 1
  641. // offset one month (December) if week starts in last year
  642. diff -= !rday.getMonth() ? 0 : 31
  643. diff /= 7
  644. yearArr.push(
  645. '<div class="row year" style="width: ' +
  646. tools.getCellSize() * (scaleUnitsThisYear - diff) +
  647. 'px;"><div class="fn-label">' +
  648. year +
  649. '</div></div>'
  650. )
  651. year++
  652. scaleUnitsThisYear = diff
  653. }
  654. scaleUnitsThisYear++
  655. // Fill months
  656. if (rday.getMonth() !== month) {
  657. // partial weeks to subtract from month header
  658. diff = rday.getDate() - 1
  659. // offset one week if week starts in last month
  660. //diff -= (diff <= 6) ? 0 : 7;
  661. diff /= 7
  662. monthArr.push(
  663. '<div class="row month" style="width:' +
  664. tools.getCellSize() * (scaleUnitsThisMonth - diff) +
  665. 'px;"><div class="fn-label">' +
  666. settings.months[month] +
  667. '</div></div>'
  668. )
  669. month = rday.getMonth()
  670. scaleUnitsThisMonth = diff
  671. }
  672. scaleUnitsThisMonth++
  673. // Fill weeks
  674. dayArr.push(
  675. '<div class="row day wd"' +
  676. ' id="' +
  677. rday.getWeekId() +
  678. '" data-offset="' +
  679. i * tools.getCellSize() +
  680. '" data-repdate="' +
  681. rday.getRepDate(settings.scale) +
  682. '">' +
  683. '<div class="fn-label">' +
  684. week +
  685. '</div></div>'
  686. )
  687. }
  688. // Last year
  689. yearArr.push(
  690. '<div class="row year" style="width: ' +
  691. tools.getCellSize() * scaleUnitsThisYear +
  692. 'px;"><div class="fn-label">' +
  693. year +
  694. '</div></div>'
  695. )
  696. // Last month
  697. monthArr.push(
  698. '<div class="row month" style="width: ' +
  699. tools.getCellSize() * scaleUnitsThisMonth +
  700. 'px"><div class="fn-label">' +
  701. settings.months[month] +
  702. '</div></div>'
  703. )
  704. dataPanel = core.dataPanel(element, dataPanelWidth)
  705. // Append panel elements
  706. dataPanel.append(
  707. $row.clone().html(yearArr.join('')),
  708. $row.clone().html(monthArr.join('')),
  709. $row.clone().html(dayArr.join(''))
  710. )
  711. break
  712. // **Months**
  713. case 'months':
  714. range = tools.parseMonthsRange(element.dateStart, element.dateEnd)
  715. dataPanelWidth = range.length * tools.getCellSize() * 3
  716. year = range[0].getFullYear()
  717. month = range[0].getMonth()
  718. for (i = 0, len = range.length; i < len; i++) {
  719. rday = range[i]
  720. // Fill years
  721. if (rday.getFullYear() !== year) {
  722. yearArr.push(
  723. '<div class="row year" style="width: ' +
  724. tools.getCellSize() * 3 * scaleUnitsThisYear +
  725. 'px;"><div class="fn-label">' +
  726. year +
  727. '</div></div>'
  728. )
  729. year = rday.getFullYear()
  730. scaleUnitsThisYear = 0
  731. }
  732. scaleUnitsThisYear++
  733. monthArr.push(
  734. '<div class="row day wd" id="dh-' +
  735. tools.genId(rday) +
  736. '" data-offset="' +
  737. i * tools.getCellSize() +
  738. '" data-repdate="' +
  739. rday.getRepDate(settings.scale) +
  740. '" style="width:72px">' +
  741. (1 + rday.getMonth()) +
  742. '</div>'
  743. )
  744. }
  745. // Last year
  746. yearArr.push(
  747. '<div class="row year" style="width: ' +
  748. tools.getCellSize() * 3 * scaleUnitsThisYear +
  749. 'px;"><div class="fn-label">' +
  750. year +
  751. '</div></div>'
  752. )
  753. dataPanel = core.dataPanel(element, dataPanelWidth)
  754. // Append panel elements
  755. dataPanel.append(
  756. $row.clone().html(yearArr.join('')),
  757. $row.clone().html(monthArr.join(''))
  758. )
  759. break
  760. // **Days (default)**
  761. default:
  762. range = tools.parseDateRange(element.dateStart, element.dateEnd)
  763. dataPanelWidth = range.length * tools.getCellSize()
  764. var dateBefore = ktkGetNextDate(range[0], -1)
  765. year = dateBefore.getFullYear()
  766. month = dateBefore.getMonth()
  767. //day = dateBefore; // <- never used?
  768. for (i = 0, len = range.length; i < len; i++) {
  769. rday = range[i]
  770. // Fill years
  771. if (rday.getFullYear() !== year) {
  772. yearArr.push(
  773. '<div class="row year" style="width:' +
  774. tools.getCellSize() * scaleUnitsThisYear +
  775. 'px;"><div class="fn-label">' +
  776. year +
  777. '</div></div>'
  778. )
  779. year = rday.getFullYear()
  780. scaleUnitsThisYear = 0
  781. }
  782. scaleUnitsThisYear++
  783. // Fill months
  784. if (rday.getMonth() !== month) {
  785. monthArr.push(
  786. '<div class="row month" style="width:' +
  787. tools.getCellSize() * scaleUnitsThisMonth +
  788. 'px;"><div class="fn-label">' +
  789. settings.months[month] +
  790. '</div></div>'
  791. )
  792. month = rday.getMonth()
  793. scaleUnitsThisMonth = 0
  794. }
  795. scaleUnitsThisMonth++
  796. day = rday.getDay()
  797. dayClass = dowClass[day]
  798. if (tools.isHoliday(rday)) {
  799. dayClass = 'holiday'
  800. }
  801. dayArr.push(
  802. '<div class="row date ' +
  803. dayClass +
  804. '"' +
  805. ' id="dh-' +
  806. tools.genId(rday) +
  807. '" data-offset="' +
  808. i * tools.getCellSize() +
  809. '" data-repdate="' +
  810. rday.getRepDate(settings.scale) +
  811. '">' +
  812. '<div class="fn-label">' +
  813. rday.getDate() +
  814. '</div></div>'
  815. )
  816. dowArr.push(
  817. '<div class="row day ' +
  818. dayClass +
  819. '"' +
  820. ' id="dw-' +
  821. tools.genId(rday) +
  822. '" data-repdate="' +
  823. rday.getRepDate(settings.scale) +
  824. '">' +
  825. '<div class="fn-label">' +
  826. settings.dow[day] +
  827. '</div></div>'
  828. )
  829. } //for
  830. // Last year
  831. yearArr.push(
  832. '<div class="row year" style="width: ' +
  833. tools.getCellSize() * scaleUnitsThisYear +
  834. 'px;"><div class="fn-label">' +
  835. year +
  836. '</div></div>'
  837. )
  838. // Last month
  839. monthArr.push(
  840. '<div class="row month" style="width: ' +
  841. (tools.getCellSize() * scaleUnitsThisMonth - 1) +
  842. 'px"><div class="fn-label">' +
  843. settings.months[month] +
  844. '</div></div>'
  845. )
  846. dataPanel = core.dataPanel(element, dataPanelWidth)
  847. // Append panel elements
  848. dataPanel.append(
  849. $row.clone().html(yearArr.join('')),
  850. $row.clone().html(monthArr.join('')),
  851. $row.clone().html(dayArr.join('')),
  852. $row.clone().html(dowArr.join(''))
  853. )
  854. }
  855. return $('<div class="rightPanel"></div>').append(dataPanel)
  856. },
  857. // **Navigation**
  858. navigation: function(element) {
  859. var ganttNavigate = null
  860. // Scrolling navigation is provided by setting
  861. // `settings.navigate='scroll'`
  862. if (settings.navigate === 'scroll') {
  863. ganttNavigate = $('<div class="navigate" />')
  864. .append(
  865. $('<div class="nav-slider" />')
  866. .append(
  867. $('<div class="nav-slider-left" />')
  868. .append(
  869. $('<button type="button" title="上一页" class="nav-link nav-page-back"/>')
  870. .html('&uarr;')
  871. .click(function() {
  872. core.navigatePage(element, -1)
  873. })
  874. )
  875. .append(
  876. $('<div class="page-number"/>').append(
  877. $('<span/>').html(element.pageNum + 1 + ' / ' + element.pageCount)
  878. )
  879. )
  880. .append(
  881. $('<button type="button" title="下一页" class="nav-link nav-page-next"/>')
  882. .html('&darr;')
  883. .click(function() {
  884. core.navigatePage(element, 1)
  885. })
  886. )
  887. .append(
  888. $('<button type="button" title="定位到当前时间" class="nav-link nav-now"/>')
  889. .html('&#9679;')
  890. .click(function() {
  891. core.navigateTo(element, 'now')
  892. })
  893. )
  894. .append(
  895. $(
  896. '<button type="button" title="快速左移查看范围" class="nav-link nav-prev-week"/>'
  897. )
  898. .html('&lt;&lt;')
  899. .click(function() {
  900. if (settings.scale === 'hours') {
  901. core.navigateTo(element, tools.getCellSize() * 8)
  902. } else if (settings.scale === 'days') {
  903. core.navigateTo(element, tools.getCellSize() * 30)
  904. } else if (settings.scale === 'weeks') {
  905. core.navigateTo(element, tools.getCellSize() * 12)
  906. } else if (settings.scale === 'months') {
  907. core.navigateTo(element, tools.getCellSize() * 6)
  908. }
  909. })
  910. )
  911. .append(
  912. $(
  913. '<button type="button" title="左移查看范围" class="nav-link nav-prev-day"/>'
  914. )
  915. .html('&lt;')
  916. .click(function() {
  917. if (settings.scale === 'hours') {
  918. core.navigateTo(element, tools.getCellSize() * 4)
  919. } else if (settings.scale === 'days') {
  920. core.navigateTo(element, tools.getCellSize() * 7)
  921. } else if (settings.scale === 'weeks') {
  922. core.navigateTo(element, tools.getCellSize() * 4)
  923. } else if (settings.scale === 'months') {
  924. core.navigateTo(element, tools.getCellSize() * 3)
  925. }
  926. })
  927. )
  928. )
  929. .append(
  930. $('<div class="nav-slider-content" />').append(
  931. $('<div class="nav-slider-bar" />')
  932. .append($('<a class="nav-slider-button" title="拖动切换查看范围"/>'))
  933. .mousedown(function(e) {
  934. e.preventDefault()
  935. element.scrollNavigation.scrollerMouseDown = true
  936. core.sliderScroll(element, e)
  937. })
  938. .mousemove(function(e) {
  939. if (element.scrollNavigation.scrollerMouseDown) {
  940. core.sliderScroll(element, e)
  941. }
  942. })
  943. )
  944. )
  945. .append(
  946. $('<div class="nav-slider-right" />')
  947. .append(
  948. $(
  949. '<button type="button" title="右移查看范围" class="nav-link nav-next-day"/>'
  950. )
  951. .html('&gt;')
  952. .click(function() {
  953. if (settings.scale === 'hours') {
  954. core.navigateTo(element, tools.getCellSize() * -4)
  955. } else if (settings.scale === 'days') {
  956. core.navigateTo(element, tools.getCellSize() * -7)
  957. } else if (settings.scale === 'weeks') {
  958. core.navigateTo(element, tools.getCellSize() * -4)
  959. } else if (settings.scale === 'months') {
  960. core.navigateTo(element, tools.getCellSize() * -3)
  961. }
  962. })
  963. )
  964. .append(
  965. $(
  966. '<button type="button" title="快速右移查看范围" class="nav-link nav-next-week"/>'
  967. )
  968. .html('&gt;&gt;')
  969. .click(function() {
  970. if (settings.scale === 'hours') {
  971. core.navigateTo(element, tools.getCellSize() * -8)
  972. } else if (settings.scale === 'days') {
  973. core.navigateTo(element, tools.getCellSize() * -30)
  974. } else if (settings.scale === 'weeks') {
  975. core.navigateTo(element, tools.getCellSize() * -12)
  976. } else if (settings.scale === 'months') {
  977. core.navigateTo(element, tools.getCellSize() * -6)
  978. }
  979. })
  980. )
  981. .append(
  982. $('<button type="button" class="nav-link nav-zoomIn"/>')
  983. .html('&#43;')
  984. .click(function() {
  985. core.zoomInOut(element, -1)
  986. })
  987. )
  988. .append(
  989. $('<button type="button" class="nav-link nav-zoomOut"/>')
  990. .html('&#45;')
  991. .click(function() {
  992. core.zoomInOut(element, 1)
  993. })
  994. )
  995. )
  996. )
  997. .append(
  998. $('<div style="display: inline-block;margin-left: 20px;"/>').html('共' + total + '条')
  999. )
  1000. $('#toToday').click(function() {
  1001. core.navigateTo(element, 'now')
  1002. })
  1003. $('#toDays')
  1004. .unbind()
  1005. .click(function() {
  1006. core.zoomInOut(element, 1)
  1007. })
  1008. $('#toWeeks').click(function() {
  1009. core.zoomInOut(element, 2)
  1010. })
  1011. $('#toMonths').click(function() {
  1012. core.zoomInOut(element, 3)
  1013. })
  1014. $('#totalCount').html(element.rowsNum / 2)
  1015. $(document).mouseup(function() {
  1016. element.scrollNavigation.scrollerMouseDown = false
  1017. })
  1018. // Button navigation is provided by setting `settings.navigation='buttons'`
  1019. } else {
  1020. ganttNavigate = $('<div class="navigate" />')
  1021. .append(
  1022. $('<button type="button" class="nav-link nav-page-back"/>')
  1023. .html('&uarr;')
  1024. .click(function() {
  1025. core.navigatePage(element, -1)
  1026. })
  1027. )
  1028. .append(
  1029. $('<div class="page-number"/>').append(
  1030. $('<span/>').html(element.pageNum + 1 + ' / ' + element.pageCount)
  1031. )
  1032. )
  1033. .append(
  1034. $('<button type="button" class="nav-link nav-page-next"/>')
  1035. .html('&darr;')
  1036. .click(function() {
  1037. core.navigatePage(element, 1)
  1038. })
  1039. )
  1040. .append(
  1041. $('<button type="button" class="nav-link nav-begin"/>')
  1042. .html('&#124;&lt;')
  1043. .click(function() {
  1044. core.navigateTo(element, 'begin')
  1045. })
  1046. )
  1047. .append(
  1048. $('<button type="button" class="nav-link nav-prev-week"/>')
  1049. .html('&lt;&lt;')
  1050. .click(function() {
  1051. core.navigateTo(element, tools.getCellSize() * 7)
  1052. })
  1053. )
  1054. .append(
  1055. $('<button type="button" class="nav-link nav-prev-day"/>')
  1056. .html('&lt;')
  1057. .click(function() {
  1058. core.navigateTo(element, tools.getCellSize())
  1059. })
  1060. )
  1061. .append(
  1062. $('<button type="button" class="nav-link nav-now"/>')
  1063. .html('&#9679;')
  1064. .click(function() {
  1065. core.navigateTo(element, 'now')
  1066. })
  1067. )
  1068. .append(
  1069. $('<button type="button" class="nav-link nav-next-day"/>')
  1070. .html('&gt;')
  1071. .click(function() {
  1072. core.navigateTo(element, tools.getCellSize() * -1)
  1073. })
  1074. )
  1075. .append(
  1076. $('<button type="button" class="nav-link nav-next-week"/>')
  1077. .html('&gt;&gt;')
  1078. .click(function() {
  1079. core.navigateTo(element, tools.getCellSize() * -7)
  1080. })
  1081. )
  1082. .append(
  1083. $('<button type="button" class="nav-link nav-end"/>')
  1084. .html('&gt;&#124;')
  1085. .click(function() {
  1086. core.navigateTo(element, 'end')
  1087. })
  1088. )
  1089. .append(
  1090. $('<button type="button" class="nav-link nav-zoomIn"/>')
  1091. .html('&#43;')
  1092. .click(function() {
  1093. core.zoomInOut(element, -1)
  1094. })
  1095. )
  1096. .append(
  1097. $('<button type="button" class="nav-link nav-zoomOut"/>')
  1098. .html('&#45;')
  1099. .click(function() {
  1100. core.zoomInOut(element, 1)
  1101. })
  1102. )
  1103. }
  1104. return $('<div class="bottom"></div>').append(ganttNavigate)
  1105. },
  1106. // **Progress Bar**
  1107. // Return an element representing a progress of position within the entire chart
  1108. createProgressBar: function(label, desc, classNames, dataObj, itemId) {
  1109. label = label || ''
  1110. var bar = $(
  1111. '<div id="' + itemId + '" class="bar"><div class="fn-label">' + label + '</div></div>'
  1112. ).data('dataObj', dataObj)
  1113. if (desc) {
  1114. bar
  1115. .mouseenter(function(e) {
  1116. if (itemId !== curItemId) {
  1117. //如过进入的不是当前组合,则直接展示新的
  1118. hiddenBar.map(function(bar, index) {
  1119. $(bar).css('top', historyTop)
  1120. })
  1121. hiddenBar = []
  1122. historyTop = null
  1123. }
  1124. isHidden = false
  1125. if (classNames != 'ganttRed' && historyTop == null) {
  1126. // 多个bar重叠时,将重叠的展示出来
  1127. var barList = document.querySelectorAll(
  1128. "[id='" +
  1129. itemId +
  1130. "'].ganttOne,[id='" +
  1131. itemId +
  1132. "'].ganttTwo,[id='" +
  1133. itemId +
  1134. "'].ganttThree"
  1135. )
  1136. var curBar = document.querySelector("[id='" + itemId + "']." + classNames)
  1137. barList.forEach(function(bar) {
  1138. if (
  1139. $(bar).css('left') == $(curBar).css('left') &&
  1140. $(bar)
  1141. .prop('className')
  1142. .indexOf(classNames) == -1
  1143. ) {
  1144. hiddenBar.push(bar)
  1145. }
  1146. })
  1147. if (hiddenBar.length > 0) {
  1148. curItemId = itemId
  1149. historyTop = $(hiddenBar[0]).css('top')
  1150. hiddenBar.map(function(bar, index) {
  1151. $(bar).css(
  1152. 'top',
  1153. parseFloat(historyTop.replace('px', '')) - (hiddenBar.length - index) * 15
  1154. )
  1155. })
  1156. }
  1157. }
  1158. var hint = $('<div class="fn-gantt-hint" />').html(desc)
  1159. $('body').append(hint)
  1160. hint.css('left', e.pageX)
  1161. hint.css('top', e.pageY - 300)
  1162. hint.show()
  1163. })
  1164. .mouseleave(function() {
  1165. isHidden = true
  1166. setTimeout(function() {
  1167. if (isHidden) {
  1168. hiddenBar.map(function(bar, index) {
  1169. $(bar).css('top', historyTop)
  1170. })
  1171. hiddenBar = []
  1172. historyTop = null
  1173. }
  1174. }, 2000)
  1175. $('.fn-gantt-hint').remove()
  1176. })
  1177. .mousemove(function(e) {
  1178. $('.fn-gantt-hint').css('left', e.pageX)
  1179. $('.fn-gantt-hint').css('top', e.pageY + 15)
  1180. })
  1181. }
  1182. if (classNames) {
  1183. bar.addClass(classNames)
  1184. }
  1185. bar.click(function(e) {
  1186. e.stopPropagation()
  1187. settings.onItemClick($(this).data('dataObj'))
  1188. })
  1189. return bar
  1190. },
  1191. // Remove the `wd` (weekday) class and add `today` class to the
  1192. // current day/week/month (depending on the current scale)
  1193. markNow: function(element) {
  1194. var cd = new Date().setHours(0, 0, 0, 0)
  1195. switch (settings.scale) {
  1196. case 'weeks':
  1197. $(element)
  1198. .find(':findweek("' + cd + '")')
  1199. .removeClass('wd')
  1200. .addClass('today')
  1201. break
  1202. case 'months':
  1203. $(element)
  1204. .find(':findmonth("' + cd + '")')
  1205. .removeClass('wd')
  1206. .addClass('today')
  1207. break
  1208. case 'days':
  1209. /* falls through */
  1210. case 'hours':
  1211. /* falls through */
  1212. default:
  1213. $(element)
  1214. .find(':findday("' + cd + '")')
  1215. .removeClass('wd')
  1216. .addClass('today')
  1217. }
  1218. },
  1219. // **Fill the Chart**
  1220. // Parse the data and fill the data panel
  1221. fillData: function(element, datapanel, leftpanel /* <- never used? */) {
  1222. var cellWidth = tools.getCellSize()
  1223. var barOffset = (cellWidth - 18) / 2
  1224. var dataPanelWidth = datapanel.width()
  1225. var invertColor = function(colStr) {
  1226. try {
  1227. colStr = colStr.replace('rgb(', '').replace(')', '')
  1228. var rgbArr = colStr.split(',')
  1229. var R = parseInt(rgbArr[0], 10)
  1230. var G = parseInt(rgbArr[1], 10)
  1231. var B = parseInt(rgbArr[2], 10)
  1232. var gray = Math.round((255 - (0.299 * R + 0.587 * G + 0.114 * B)) * 0.9)
  1233. return 'rgb(' + gray + ', ' + gray + ', ' + gray + ')'
  1234. } catch (err) {
  1235. return ''
  1236. }
  1237. }
  1238. // Loop through the values of each data element and set a row
  1239. var indexNum = 0
  1240. $.each(element.data, function(i, entry) {
  1241. if (
  1242. i >= element.pageNum * settings.itemsPerPage &&
  1243. i < element.pageNum * settings.itemsPerPage + settings.itemsPerPage
  1244. ) {
  1245. $.each(entry.values, function(j, day) {
  1246. var _bar
  1247. var from, to, cFrom, cTo, dFrom, dTo, dl, dp
  1248. var topEl, top
  1249. switch (settings.scale) {
  1250. // **Hourly data**
  1251. case 'hours':
  1252. dFrom = tools.genId(tools.dateDeserialize(day.from), element.scaleStep)
  1253. from = $(element).find('#dh-' + dFrom)
  1254. dTo = tools.genId(tools.dateDeserialize(day.to), element.scaleStep)
  1255. to = $(element).find('#dh-' + dTo)
  1256. cFrom = from.data('offset')
  1257. cTo = to.data('offset')
  1258. dl = Math.floor((cTo - cFrom) / cellWidth) + 1
  1259. dp = (100 * (cellWidth * dl - 1)) / dataPanelWidth
  1260. _bar = core.createProgressBar(
  1261. day.label,
  1262. day.desc,
  1263. day.customClass,
  1264. day.dataObj,
  1265. day.itemId
  1266. )
  1267. // find row
  1268. topEl = $(element).find('#rowheader' + i)
  1269. top = cellWidth * 5 + barOffset + topEl.data('offset')
  1270. _bar.css({
  1271. top: top,
  1272. left: Math.floor(cFrom),
  1273. width: dp + '%',
  1274. display: !cFrom && !cTo ? 'none' : '',
  1275. })
  1276. datapanel.append(_bar)
  1277. break
  1278. // **Weekly data**
  1279. case 'weeks':
  1280. dFrom = tools.dateDeserialize(day.from)
  1281. dTo = tools.dateDeserialize(day.to)
  1282. from = $(element).find('#' + dFrom.getWeekId())
  1283. cFrom = from.data('offset')
  1284. to = $(element).find('#' + dTo.getWeekId())
  1285. cTo = to.data('offset')
  1286. dl = Math.round((cTo - cFrom) / cellWidth) + 1
  1287. dp = (100 * (cellWidth * dl - 1)) / dataPanelWidth
  1288. // 如果没有开始或者结束,则不显示
  1289. if (!cTo | !cFrom) dp = 0
  1290. if (dp < 0) dp = 100
  1291. _bar = core.createProgressBar(
  1292. day.label,
  1293. day.desc,
  1294. day.customClass,
  1295. day.dataObj,
  1296. day.itemId
  1297. )
  1298. // find row
  1299. topEl = $(element).find('#rowheader' + i)
  1300. top = cellWidth * (3 + j) + barOffset + topEl.data('offset') + indexNum * 24
  1301. _bar.css({
  1302. top: top,
  1303. left: Math.floor(cFrom),
  1304. width: dp + '%',
  1305. display: !cFrom && !cTo ? 'none' : '',
  1306. })
  1307. datapanel.append(_bar)
  1308. break
  1309. // **Monthly data**
  1310. case 'months':
  1311. dFrom = tools.dateDeserialize(day.from)
  1312. dTo = tools.dateDeserialize(day.to)
  1313. if (dFrom.getDate() <= 3 && dFrom.getMonth() === 0) {
  1314. dFrom.setDate(dFrom.getDate() + 4)
  1315. }
  1316. if (dFrom.getDate() <= 3 && dFrom.getMonth() === 0) {
  1317. dFrom.setDate(dFrom.getDate() + 4)
  1318. }
  1319. if (dTo.getDate() <= 3 && dTo.getMonth() === 0) {
  1320. dTo.setDate(dTo.getDate() + 4)
  1321. }
  1322. from = $(element).find('#dh-' + tools.genId(dFrom))
  1323. cFrom = from.data('offset')
  1324. to = $(element).find('#dh-' + tools.genId(dTo))
  1325. cTo = to.data('offset')
  1326. dl = Math.round((cTo - cFrom) / cellWidth) + 1
  1327. dp = (100 * (cellWidth * dl - 1)) / dataPanelWidth
  1328. // 如果没有开始或者结束,则不显示
  1329. if (!cTo | !cFrom) dp = 0
  1330. if (dp < 0) dp = 100
  1331. _bar = core.createProgressBar(
  1332. day.label,
  1333. day.desc,
  1334. day.customClass,
  1335. day.dataObj,
  1336. day.itemId
  1337. )
  1338. // find row
  1339. topEl = $(element).find('#rowheader' + i)
  1340. top = cellWidth * (2 + j) + barOffset + topEl.data('offset') + indexNum * 24
  1341. _bar.css({
  1342. top: top,
  1343. left: Math.floor(cFrom) * 3,
  1344. width: dp * 3 + '%',
  1345. display: !cFrom && !cTo ? 'none' : '',
  1346. })
  1347. datapanel.append(_bar)
  1348. break
  1349. // **Days**
  1350. case 'days':
  1351. /* falls through */
  1352. default:
  1353. dFrom = tools.genId(tools.dateDeserialize(day.from))
  1354. dTo = tools.genId(tools.dateDeserialize(day.to))
  1355. from = $(element).find('#dh-' + dFrom)
  1356. cFrom = from.data('offset')
  1357. dl = Math.floor((dTo - dFrom) / UTC_DAY_IN_MS) + 1
  1358. dp = (100 * (cellWidth * dl - 1)) / dataPanelWidth
  1359. _bar = core.createProgressBar(
  1360. day.label,
  1361. day.desc,
  1362. day.customClass,
  1363. day.dataObj,
  1364. day.itemId
  1365. )
  1366. // find row
  1367. topEl = $(element).find('#rowheader' + i)
  1368. top = cellWidth * (4 + j) + barOffset + topEl.data('offset') + indexNum * 24
  1369. _bar.css({
  1370. top: top,
  1371. left: Math.floor(cFrom),
  1372. width: dp + '%',
  1373. display: !cFrom && !cTo ? 'none' : '',
  1374. })
  1375. datapanel.append(_bar)
  1376. }
  1377. var $l = _bar.find('.fn-label')
  1378. if ($l.length) {
  1379. var gray = invertColor(_bar.css('backgroundColor'))
  1380. $l.css('color', gray)
  1381. }
  1382. // if (j === 0) {
  1383. // indexNum++
  1384. // }
  1385. })
  1386. indexNum++
  1387. }
  1388. })
  1389. },
  1390. // **Navigation**
  1391. navigateTo: function(element, val) {
  1392. var $rightPanel = $(element).find('.fn-gantt .rightPanel')
  1393. var $dataPanel = $rightPanel.find('.dataPanel')
  1394. var rightPanelWidth = $rightPanel.width()
  1395. var dataPanelWidth = $dataPanel.width()
  1396. var shift = function() {
  1397. core.repositionLabel(element)
  1398. }
  1399. var maxLeft, curLeft
  1400. switch (val) {
  1401. case 'begin':
  1402. $dataPanel.animate({ left: '0' }, 'fast', shift)
  1403. element.scrollNavigation.panelMargin = 0
  1404. break
  1405. case 'end':
  1406. var pLeft = dataPanelWidth - rightPanelWidth
  1407. element.scrollNavigation.panelMargin = pLeft * -1
  1408. $dataPanel.animate({ left: '-' + pLeft }, 'fast', shift)
  1409. break
  1410. case 'now':
  1411. if (!element.scrollNavigation.canScroll || !$dataPanel.find('.today').length) {
  1412. return false
  1413. }
  1414. maxLeft = (dataPanelWidth - rightPanelWidth) * -1
  1415. curLeft = $dataPanel.css('left').replace('px', '')
  1416. val = $dataPanel.find('.today').offset().left - $dataPanel.offset().left
  1417. val *= -1
  1418. if (val > 0) {
  1419. val = 0
  1420. } else if (val < maxLeft) {
  1421. val = maxLeft
  1422. }
  1423. $dataPanel.animate({ left: val }, 'fast', shift)
  1424. element.scrollNavigation.panelMargin = val
  1425. break
  1426. default:
  1427. maxLeft = (dataPanelWidth - rightPanelWidth) * -1
  1428. curLeft = $dataPanel.css('left').replace('px', '')
  1429. val = parseInt(curLeft, 10) + val
  1430. if (val <= 0 && val >= maxLeft) {
  1431. $dataPanel.animate({ left: val }, 'fast', shift)
  1432. }
  1433. element.scrollNavigation.panelMargin = val
  1434. }
  1435. core.synchronizeScroller(element)
  1436. },
  1437. // Navigate to a specific page
  1438. navigatePage: function(element, val) {
  1439. if (
  1440. element.pageNum + val >= 0 &&
  1441. element.pageNum + val < Math.ceil(element.rowsNum / settings.itemsPerPage)
  1442. ) {
  1443. core.waitToggle(element, function() {
  1444. element.pageNum += val
  1445. element.hPosition = $('.fn-gantt .dataPanel')
  1446. .css('left')
  1447. .replace('px', '')
  1448. element.scaleOldWidth = false
  1449. core.init(element)
  1450. })
  1451. }
  1452. },
  1453. // Change zoom level
  1454. zoomInOut: function(element, val) {
  1455. core.waitToggle(element, function() {
  1456. var scale = settings.scale
  1457. var headerRows = element.headerRows
  1458. var scaleSt = element.scaleStep
  1459. if (val == 1) {
  1460. scale = 'days'
  1461. headerRows = 4
  1462. scaleSt = 13
  1463. }
  1464. if (val == 2) {
  1465. scale = 'weeks'
  1466. headerRows = 3
  1467. scaleSt = 13
  1468. }
  1469. if (val == 3) {
  1470. scale = 'months'
  1471. headerRows = 2
  1472. scaleSt = 14
  1473. }
  1474. /* var zoomIn = (val < 0);
  1475. var scaleSt = element.scaleStep + val * 3;
  1476. scaleSt = scaleSt <= 1 ? 1 : scaleSt === 4 ? 3 : scaleSt;
  1477. var scale = settings.scale;
  1478. var headerRows = element.headerRows;
  1479. if (settings.scale === "hours" && scaleSt >= 13) {
  1480. scale = "days";
  1481. headerRows = 4;
  1482. scaleSt = 13;
  1483. } else if (settings.scale === "days" && zoomIn) {
  1484. scale = "hours";
  1485. headerRows = 5;
  1486. scaleSt = 12;
  1487. } else if (settings.scale === "days" && !zoomIn) {
  1488. scale = "weeks";
  1489. headerRows = 3;
  1490. scaleSt = 13;
  1491. } else if (settings.scale === "weeks" && !zoomIn) {
  1492. scale = "months";
  1493. headerRows = 2;
  1494. scaleSt = 14;
  1495. } else if (settings.scale === "weeks" && zoomIn) {
  1496. scale = "days";
  1497. headerRows = 4;
  1498. scaleSt = 13;
  1499. } else if (settings.scale === "months" && zoomIn) {
  1500. scale = "weeks";
  1501. headerRows = 3;
  1502. scaleSt = 13;
  1503. }
  1504. // do nothing if attempting to zoom past max/min
  1505. if ((zoomIn && $.inArray(scale, scales) < $.inArray(settings.minScale, scales)) ||
  1506. (!zoomIn && $.inArray(scale, scales) > $.inArray(settings.maxScale, scales))) {
  1507. core.init(element);
  1508. return;
  1509. }*/
  1510. element.scaleStep = scaleSt
  1511. settings.scale = scale
  1512. element.headerRows = headerRows
  1513. var $rightPanel = $(element).find('.fn-gantt .rightPanel')
  1514. var $dataPanel = $rightPanel.find('.dataPanel')
  1515. element.hPosition = $dataPanel.css('left').replace('px', '')
  1516. element.scaleOldWidth = $dataPanel.width() - $rightPanel.width()
  1517. if (settings.useCookie) {
  1518. $.cookie(settings.cookieKey + 'CurrentScale', settings.scale)
  1519. // reset scrollPos
  1520. $.cookie(settings.cookieKey + 'ScrollPos', null)
  1521. }
  1522. core.init(element)
  1523. })
  1524. },
  1525. // Move chart via mouseclick
  1526. mouseScroll: function(element, e) {
  1527. var $dataPanel = $(element).find('.fn-gantt .dataPanel')
  1528. $dataPanel.css('cursor', 'move')
  1529. var bPos = $dataPanel.offset()
  1530. var mPos =
  1531. element.scrollNavigation.mouseX === null ? e.pageX : element.scrollNavigation.mouseX
  1532. var delta = e.pageX - mPos
  1533. element.scrollNavigation.mouseX = e.pageX
  1534. core.scrollPanel(element, delta)
  1535. clearTimeout(element.scrollNavigation.repositionDelay)
  1536. element.scrollNavigation.repositionDelay = setTimeout(core.repositionLabel, 50, element)
  1537. },
  1538. // Move chart via mousewheel
  1539. wheelScroll: function(element, e) {
  1540. e.preventDefault() // e is a jQuery Event
  1541. // attempts to normalize scroll wheel velocity
  1542. var delta =
  1543. 'detail' in e
  1544. ? e.detail
  1545. : 'wheelDelta' in e.originalEvent
  1546. ? (-1 / 120) * e.originalEvent.wheelDelta
  1547. : e.originalEvent.deltaY
  1548. ? e.originalEvent.deltaY / Math.abs(e.originalEvent.deltaY)
  1549. : e.originalEvent.detail
  1550. // simpler normalization, ignoring per-device/browser/platform acceleration & semantic variations
  1551. //var delta = e.detail || - (e = e.originalEvent).wheelData || e.deltaY /* || e.deltaX */ || e.detail;
  1552. //delta = ( delta / Math.abs(delta) ) || 0;
  1553. core.scrollPanel(element, -50 * delta)
  1554. clearTimeout(element.scrollNavigation.repositionDelay)
  1555. element.scrollNavigation.repositionDelay = setTimeout(core.repositionLabel, 50, element)
  1556. },
  1557. // Move chart via slider control
  1558. sliderScroll: function(element, e) {
  1559. var $sliderBar = $(element).find('.nav-slider-bar')
  1560. var $sliderBarBtn = $sliderBar.find('.nav-slider-button')
  1561. var $rightPanel = $(element).find('.fn-gantt .rightPanel')
  1562. var $dataPanel = $rightPanel.find('.dataPanel')
  1563. var bPos = $sliderBar.offset()
  1564. var bWidth = $sliderBar.width()
  1565. var wButton = $sliderBarBtn.width()
  1566. var pos, pLeft
  1567. if (e.pageX >= bPos.left && e.pageX <= bPos.left + bWidth) {
  1568. pos = e.pageX - bPos.left
  1569. pos = pos - wButton / 2
  1570. $sliderBarBtn.css('left', pos)
  1571. pLeft = $dataPanel.width() - $rightPanel.width()
  1572. var pPos = ((pos * pLeft) / bWidth) * -1
  1573. if (pPos >= 0) {
  1574. $dataPanel.css('left', '0')
  1575. element.scrollNavigation.panelMargin = 0
  1576. } else if (pos >= bWidth - wButton * 1) {
  1577. $dataPanel.css('left', pLeft * -1)
  1578. element.scrollNavigation.panelMargin = pLeft * -1
  1579. } else {
  1580. $dataPanel.css('left', pPos)
  1581. element.scrollNavigation.panelMargin = pPos
  1582. }
  1583. clearTimeout(element.scrollNavigation.repositionDelay)
  1584. element.scrollNavigation.repositionDelay = setTimeout(core.repositionLabel, 5, element)
  1585. }
  1586. },
  1587. // Update scroll panel margins
  1588. scrollPanel: function(element, delta) {
  1589. if (!element.scrollNavigation.canScroll) {
  1590. return false
  1591. }
  1592. var _panelMargin = parseInt(element.scrollNavigation.panelMargin, 10) + delta
  1593. if (_panelMargin > 0) {
  1594. element.scrollNavigation.panelMargin = 0
  1595. $(element)
  1596. .find('.fn-gantt .dataPanel')
  1597. .css('left', element.scrollNavigation.panelMargin)
  1598. } else if (_panelMargin < element.scrollNavigation.panelMaxPos * -1) {
  1599. element.scrollNavigation.panelMargin = element.scrollNavigation.panelMaxPos * -1
  1600. $(element)
  1601. .find('.fn-gantt .dataPanel')
  1602. .css('left', element.scrollNavigation.panelMargin)
  1603. } else {
  1604. element.scrollNavigation.panelMargin = _panelMargin
  1605. $(element)
  1606. .find('.fn-gantt .dataPanel')
  1607. .css('left', element.scrollNavigation.panelMargin)
  1608. }
  1609. core.synchronizeScroller(element)
  1610. },
  1611. // Synchronize scroller
  1612. synchronizeScroller: function(element) {
  1613. if (settings.navigate !== 'scroll') {
  1614. return
  1615. }
  1616. var $rightPanel = $(element).find('.fn-gantt .rightPanel')
  1617. var $dataPanel = $rightPanel.find('.dataPanel')
  1618. var $sliderBar = $(element).find('.nav-slider-bar')
  1619. var $sliderBtn = $sliderBar.find('.nav-slider-button')
  1620. var bWidth = $sliderBar.width()
  1621. var wButton = $sliderBtn.width()
  1622. var pLeft = $dataPanel.width() - $rightPanel.width()
  1623. var hPos = $dataPanel.css('left') || 0
  1624. if (hPos) {
  1625. hPos = hPos.replace('px', '')
  1626. }
  1627. var pos = (hPos * bWidth) / pLeft - $sliderBtn.width() * 0.25
  1628. pos =
  1629. pos > 0 ? 0 : pos * -1 >= bWidth - wButton * 0.75 ? (bWidth - wButton * 1.25) * -1 : pos
  1630. $sliderBtn.css('left', pos * -1)
  1631. },
  1632. // Reposition data labels
  1633. repositionLabel: function(element) {
  1634. setTimeout(function() {
  1635. var $dataPanel
  1636. if (!element) {
  1637. $dataPanel = $('.fn-gantt .rightPanel .dataPanel')
  1638. } else {
  1639. var $rightPanel = $(element).find('.fn-gantt .rightPanel')
  1640. $dataPanel = $rightPanel.find('.dataPanel')
  1641. }
  1642. if (settings.useCookie) {
  1643. $.cookie(settings.cookieKey + 'ScrollPos', $dataPanel.css('left').replace('px', ''))
  1644. }
  1645. }, 500)
  1646. },
  1647. // waitToggle
  1648. waitToggle: function(element, showCallback) {
  1649. if ($.isFunction(showCallback)) {
  1650. var $elt = $(element)
  1651. var eo = $elt.offset()
  1652. var ew = $elt.outerWidth()
  1653. var eh = $elt.outerHeight()
  1654. if (!element.loader) {
  1655. element.loader = $(
  1656. '<div class="fn-gantt-loader">' +
  1657. '<div class="fn-gantt-loader-spinner"><span>' +
  1658. settings.waitText +
  1659. '</span></div></div>'
  1660. )
  1661. }
  1662. $elt.append(element.loader)
  1663. setTimeout(showCallback, 500)
  1664. } else if (element.loader) {
  1665. element.loader.detach()
  1666. }
  1667. },
  1668. }
  1669. // Utility functions
  1670. // =================
  1671. var tools = {
  1672. // Return the maximum available date in data depending on the scale
  1673. getMaxDate: function(element) {
  1674. var maxDate = null
  1675. $.each(element.data, function(i, entry) {
  1676. $.each(entry.values, function(i, date) {
  1677. maxDate =
  1678. maxDate < tools.dateDeserialize(date.to) ? tools.dateDeserialize(date.to) : maxDate
  1679. })
  1680. })
  1681. maxDate = maxDate || new Date()
  1682. var bd
  1683. bd = new Date(maxDate.getTime())
  1684. maxDate = new Date(bd.getFullYear() + 1, 2, 31)
  1685. /*switch (settings.scale) {
  1686. case "hours":
  1687. maxDate.setHours(Math.ceil((maxDate.getHours()) / element.scaleStep) * element.scaleStep);
  1688. maxDate.setHours(maxDate.getHours() + element.scaleStep * 3);
  1689. break;
  1690. case "weeks":
  1691. // wtf is happening here?
  1692. bd = new Date(maxDate.getTime());
  1693. bd = new Date(bd.setDate(bd.getDate() + 3 * 7));
  1694. var md = Math.floor(bd.getDate() / 7) * 7;
  1695. maxDate = new Date(bd.getFullYear(), bd.getMonth(), md === 0 ? 4 : md - 3);
  1696. break;
  1697. case "months":
  1698. bd = new Date(maxDate.getFullYear(), maxDate.getMonth(), 1);
  1699. bd.setMonth(bd.getMonth() + 2);
  1700. maxDate = new Date(bd.getFullYear(), bd.getMonth(), 1);
  1701. break;
  1702. case "days":
  1703. falls through
  1704. default:
  1705. maxDate.setHours(0);
  1706. maxDate.setDate(maxDate.getDate() + 3);
  1707. }*/
  1708. return maxDate
  1709. },
  1710. // Return the minimum available date in data depending on the scale
  1711. getMinDate: function(element) {
  1712. var minDate = null
  1713. $.each(element.data, function(i, entry) {
  1714. $.each(entry.values, function(i, date) {
  1715. minDate =
  1716. minDate > tools.dateDeserialize(date.from) || minDate === null
  1717. ? tools.dateDeserialize(date.from)
  1718. : minDate
  1719. })
  1720. })
  1721. minDate = minDate || new Date()
  1722. var bd = null
  1723. bd = new Date(minDate.getTime())
  1724. minDate = new Date(bd.getFullYear() - 1, 9, 1)
  1725. /* switch (settings.scale) {
  1726. case "hours":
  1727. minDate.setHours(Math.floor((minDate.getHours()) / element.scaleStep) * element.scaleStep);
  1728. minDate.setHours(minDate.getHours() - element.scaleStep * 3);
  1729. break;
  1730. case "weeks":
  1731. // wtf is happening here?
  1732. var bd = new Date(minDate.getTime());
  1733. bd = new Date(bd.setDate(bd.getDate() - 3 * 7));
  1734. var md = Math.floor(bd.getDate() / 7) * 7;
  1735. minDate = new Date(bd.getFullYear(), bd.getMonth(), md === 0 ? 4 : md - 3);
  1736. break;
  1737. case "months":
  1738. minDate.setHours(0, 0, 0, 0);
  1739. minDate.setDate(1);
  1740. minDate.setMonth(minDate.getMonth() - 3);
  1741. break;
  1742. case "days":
  1743. falls through
  1744. default:
  1745. minDate.setHours(0, 0, 0, 0);
  1746. minDate.setDate(minDate.getDate() - 3);
  1747. }*/
  1748. return minDate
  1749. },
  1750. // Return an array of Date objects between `from` and `to`
  1751. parseDateRange: function(from, to) {
  1752. var current = new Date(from.getTime())
  1753. var ret = []
  1754. var i = 0
  1755. do {
  1756. ret[i++] = new Date(current.getTime())
  1757. current.setDate(current.getDate() + 1)
  1758. } while (current <= to)
  1759. return ret
  1760. },
  1761. // Return an array of Date objects between `from` and `to`,
  1762. // scaled hourly
  1763. parseTimeRange: function(from, to, scaleStep) {
  1764. var current = new Date(from)
  1765. var end = new Date(to)
  1766. // GR: Fix begin
  1767. current.setHours(0, 0, 0, 0)
  1768. end.setMilliseconds(0)
  1769. end.setSeconds(0)
  1770. if (end.getMinutes() > 0 || end.getHours() > 0) {
  1771. end.setMinutes(0)
  1772. end.setHours(0)
  1773. end.setTime(end.getTime() + UTC_DAY_IN_MS)
  1774. }
  1775. // GR: Fix end
  1776. var ret = []
  1777. var i = 0
  1778. for (;;) {
  1779. var dayStartTime = new Date(current)
  1780. dayStartTime.setHours(Math.floor(current.getHours() / scaleStep) * scaleStep)
  1781. if (ret[i] && dayStartTime.getDay() !== ret[i].getDay()) {
  1782. // If mark-cursor jumped to next day, make sure it starts at 0 hours
  1783. dayStartTime.setHours(0)
  1784. }
  1785. ret[i] = dayStartTime
  1786. // Note that we use ">" because we want to include the end-time point.
  1787. if (current > to) {
  1788. break
  1789. }
  1790. /* BUG-2: current is moved backwards producing a dead-lock! (crashes chrome/IE/firefox)
  1791. * SEE: https://github.com/taitems/jQuery.Gantt/issues/62
  1792. if (current.getDay() !== ret[i].getDay()) {
  1793. current.setHours(0);
  1794. }
  1795. */
  1796. // GR Fix Begin
  1797. current = ktkGetNextDate(dayStartTime, scaleStep)
  1798. // GR Fix End
  1799. i++
  1800. }
  1801. return ret
  1802. },
  1803. // Return an array of Date objects between a range of weeks
  1804. // between `from` and `to`
  1805. parseWeeksRange: function(from, to) {
  1806. var current = from.getDayForWeek()
  1807. var ret = []
  1808. var i = 0
  1809. do {
  1810. ret[i++] = current.getDayForWeek()
  1811. current.setDate(current.getDate() + 7)
  1812. } while (current <= to)
  1813. return ret
  1814. },
  1815. // Return an array of Date objects between a range of months
  1816. // between `from` and `to`
  1817. parseMonthsRange: function(from, to) {
  1818. var current = new Date(from)
  1819. var end = new Date(to) // <- never used?
  1820. var ret = []
  1821. var i = 0
  1822. do {
  1823. ret[i++] = new Date(current.getFullYear(), current.getMonth(), 1)
  1824. current.setMonth(current.getMonth() + 1)
  1825. } while (current <= to)
  1826. return ret
  1827. },
  1828. // Deserialize a date from a string or integer
  1829. dateDeserialize: function(date) {
  1830. if (typeof date === 'string') {
  1831. date = date.replace(/\/Date\((.*)\)\//, '$1')
  1832. date = $.isNumeric(date) ? parseInt(date, 10) : $.trim(date)
  1833. }
  1834. return new Date(date)
  1835. },
  1836. // Generate an id for a date
  1837. genId: function(t) {
  1838. // varargs
  1839. if ($.isNumeric(t)) {
  1840. t = new Date(t)
  1841. }
  1842. switch (settings.scale) {
  1843. case 'hours':
  1844. var hour = t.getHours()
  1845. if (arguments.length >= 2) {
  1846. hour = Math.floor(t.getHours() / arguments[1]) * arguments[1]
  1847. }
  1848. return new Date(t.getFullYear(), t.getMonth(), t.getDate(), hour).getTime()
  1849. case 'weeks':
  1850. var y = t.getFullYear()
  1851. var w = t.getWeekOfYear()
  1852. var m = t.getMonth()
  1853. if (m === 11 && w === 1) {
  1854. y++
  1855. } else if (!m && w > 51) {
  1856. y--
  1857. }
  1858. return y + '-' + w
  1859. case 'months':
  1860. return t.getFullYear() + '-' + t.getMonth()
  1861. case 'days':
  1862. /* falls through */
  1863. default:
  1864. return new Date(t.getFullYear(), t.getMonth(), t.getDate()).getTime()
  1865. }
  1866. },
  1867. // normalizes an array of dates into a map of start-of-day millisecond values
  1868. _datesToDays: function(dates) {
  1869. var dayMap = {}
  1870. for (var i = 0, len = dates.length, day; i < len; i++) {
  1871. day = tools.dateDeserialize(dates[i])
  1872. dayMap[day.setHours(0, 0, 0, 0)] = true
  1873. }
  1874. return dayMap
  1875. },
  1876. // Returns true when the given date appears in the array of holidays, if provided
  1877. isHoliday: (function() {
  1878. // IIFE
  1879. // short-circuits the function if no holidays option was passed
  1880. if (!settings.holidays || !settings.holidays.length) {
  1881. return function() {
  1882. return false
  1883. }
  1884. }
  1885. var holidays = false
  1886. // returns the function that will be used to check for holidayness of a given date
  1887. return function(date) {
  1888. if (!holidays) {
  1889. holidays = tools._datesToDays(settings.holidays)
  1890. }
  1891. return !!holidays[
  1892. // assumes numeric dates are already normalized to start-of-day
  1893. $.isNumeric(date)
  1894. ? date
  1895. : new Date(date.getFullYear(), date.getMonth(), date.getDate()).getTime()
  1896. ]
  1897. }
  1898. })(),
  1899. // Get the current cell height
  1900. getCellSize: function() {
  1901. if (typeof tools._getCellSize === 'undefined') {
  1902. var measure = $(
  1903. '<div style="display: none; position: absolute;" class="fn-gantt"><div class="row"></div></div>'
  1904. )
  1905. $('body').append(measure)
  1906. tools._getCellSize = measure.find('.row').height()
  1907. measure.empty().remove()
  1908. }
  1909. return tools._getCellSize
  1910. },
  1911. // Get the current page height
  1912. getPageHeight: function(element) {
  1913. return element.pageNum + 1 === element.pageCount
  1914. ? element.rowsOnLastPage * tools.getCellSize()
  1915. : settings.itemsPerPage * tools.getCellSize()
  1916. },
  1917. }
  1918. this.each(function() {
  1919. this.data = null // Received data
  1920. this.pageNum = 0 // Current page number
  1921. this.pageCount = 0 // Available pages count
  1922. this.rowsOnLastPage = 0 // How many rows on last page
  1923. this.rowsNum = 0 // Number of total rows
  1924. this.hPosition = 0 // Current position on diagram (Horizontal)
  1925. this.dateStart = null
  1926. this.dateEnd = null
  1927. this.scrollClicked = false
  1928. this.scaleOldWidth = null
  1929. this.headerRows = null
  1930. // Update cookie with current scale
  1931. if (settings.useCookie) {
  1932. var sc = $.cookie(settings.cookieKey + 'CurrentScale')
  1933. if (sc) {
  1934. settings.scale = sc
  1935. } else {
  1936. $.cookie(settings.cookieKey + 'CurrentScale', settings.scale)
  1937. }
  1938. }
  1939. switch (settings.scale) {
  1940. //case "hours":
  1941. // this.headerRows = 5;
  1942. // this.scaleStep = 8;
  1943. // break;
  1944. case 'hours':
  1945. this.headerRows = 5
  1946. this.scaleStep = 1
  1947. break
  1948. case 'weeks':
  1949. this.headerRows = 3
  1950. this.scaleStep = 13
  1951. break
  1952. case 'months':
  1953. this.headerRows = 2
  1954. this.scaleStep = 14
  1955. break
  1956. case 'days':
  1957. /* falls through */
  1958. default:
  1959. this.headerRows = 4
  1960. this.scaleStep = 13
  1961. }
  1962. this.scrollNavigation = {
  1963. panelMouseDown: false,
  1964. scrollerMouseDown: false,
  1965. mouseX: null,
  1966. panelMargin: 0,
  1967. repositionDelay: 0,
  1968. panelMaxPos: 0,
  1969. canScroll: true,
  1970. }
  1971. this.gantt = null
  1972. this.loader = null
  1973. core.create(this)
  1974. })
  1975. }
  1976. })(jQuery)