diff --git a/.gitignore b/.gitignore index e43b0f9..a6dfed0 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,3 @@ .DS_Store +.idea/ +*.iml \ No newline at end of file diff --git a/.project b/.project new file mode 100644 index 0000000..df43370 --- /dev/null +++ b/.project @@ -0,0 +1,17 @@ + + + jQuery.Gantt + jQuery gantt chart + + + + + org.eclipse.wst.jsdt.core.javascriptValidator + + + + + + org.eclipse.wst.jsdt.core.jsNature + + diff --git a/.settings/org.eclipse.core.resources.prefs b/.settings/org.eclipse.core.resources.prefs new file mode 100644 index 0000000..63065a0 --- /dev/null +++ b/.settings/org.eclipse.core.resources.prefs @@ -0,0 +1,3 @@ +eclipse.preferences.version=1 +encoding//js/jquery.fn.gantt.js=UTF-8 +encoding//js/jquery.fn.gantt.min.js=UTF-8 diff --git a/css/style.css b/css/style.css index 0756dfe..64ef580 100644 --- a/css/style.css +++ b/css/style.css @@ -49,9 +49,6 @@ line-height: 24px; margin-left: -1px; } -.fn-gantt .row.header { - margin-left: 0; -} .fn-gantt .leftPanel .fn-label { display: inline-block; @@ -110,6 +107,7 @@ background-position: 24px 24px; position: relative; } + .fn-gantt .day, .fn-gantt .date { overflow: visible; width: 24px; @@ -224,6 +222,13 @@ color: #778461 !important; } +.fn-gantt .ganttGray { + background-color: #CCCCCC; +} +.fn-gantt .ganttGray .fn-label { + color: #626184 !important; +} + .fn-gantt .ganttOrange { background-color: #FCD29A; } @@ -231,13 +236,36 @@ color: #714715 !important; } +.fn-gantt .depLine { + background-color: transparent; + position: absolute; + z-index: 9999; +} + +.fn-gantt .depLineSh { + margin-top: 2px; + margin-left: 2px; + opacity: 0.3; +} + +.fn-gantt .depStart, .fn-gantt .depEnd { + position: absolute; + width: 5px; + height: 5px; + -webkit-border-radius: 50%; + -moz-border-radius: 50%; + border-radius: 50%; + border: 2px solid #fff; + -webkit-box-shadow: 1px 1px 1px 0px #444; + box-shadow: 1px 1px 1px 0px #444; + z-index: 10001; +} /* === BOTTOM NAVIGATION === */ .fn-gantt .bottom { clear: both; background-color: #f6f6f6; - width: 100%; } .fn-gantt .navigate { border-top: 1px solid #DDD; diff --git a/index.html b/index.html index 506adad..69ed097 100644 --- a/index.html +++ b/index.html @@ -1,600 +1,563 @@ - + jQuery.Gantt - - - - - - - + + + + + + -
+
-

- jQuery.Gantt - — Draw Gantt charts with the famous jQuery ease of development -

+

+ jQuery.Gantt + — Draw Gantt charts with the famous jQuery ease of development +

-

Contributors

- +

Contributors

+ -

- Example -

+

+ Example +

-
+
-

- Gantt Configuration -

+

+ Gantt Configuration +

-
+
 $(".selector").gantt({
-    source: "ajax/data.json",
-    scale: "weeks",
-    minScale: "weeks",
-    maxScale: "months",
-    onItemClick: function(data) {
-        alert("Item clicked - show some details");
-    },
-    onAddClick: function(dt, rowId) {
-        alert("Empty space clicked - add an item!");
-    },
-    onRender: function() {
-        console.log("chart rendered");
-    }
+	source: "ajax/data.json",
+	scale: "weeks",
+	minScale: "weeks",
+	maxScale: "months",
+	onItemClick: function(data) {
+		alert("Item clicked - show some details");
+	},
+	onAddClick: function(dt, rowId) {
+		alert("Empty space clicked - add an item!");
+	},
+	onRender: function() {
+		console.log("chart rendered");
+	}
 });
 
- - +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+ Parameter + + Default + + Accepts Type +
+ source + + [] + + Array, String (url) +
+ itemsPerPage + + 7 + + Number +
+ months + + ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"] + + Array +
+ dow + + ["S", "M", "T", "W", "T", "F", "S"] + + Array +
+ navigate + + "buttons" + + String ("buttons","scroll") +
+ scale + + "days" + + String +
+ maxScale + + "months" + + String +
+ minScale + + "hours" + + String +
+ waitText + + "Please Wait..." + + String +
+ onItemClick + + function (data) { return; } + a JS Function that gets called when clicking on a Gantt-Item.
The parameter passed to the function is the dataObj of the item
+ onAddClick + function (dt, rowId) { return; } + a JS Function that gets called when clicking on a Gantt-Item.
The parameter passed to the function is the DateTime in ms for the clicked Cell, and the ID if the source object (row)
+ onRender + function () { return; } + a JS Function called whenever the chart is (re)rendered
- Parameter - - Default - - Accepts Type -
- source - - [] - - Array, string (url) -
- itemsPerPage - - 7 - - number -
- months - - ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"] - - Array (12 strings representing the months of the year) -
- dow - - ["S", "M", "T", "W", "T", "F", "S"] - - Array (7 strings representing the days of the week) -
- holidays - - undefined - - Array of numbers (ms), date strings (see formats), or Date objects -
- navigate - - "buttons" - - string ("buttons","scroll") -
- scale - - "days" - - string ("months","weeks","days","hours") -
- maxScale - - "months" - - string ("months","weeks","days","hours") -
- minScale - - "hours" - - string ("months","weeks","days","hours") -
- waitText - - "Please wait..." - - string -
- onItemClick - - function (data) { return; } - Function called when clicking on a Gantt item.
The parameter passed to the function is the dataObj of the source item, if one was provided.
- onAddClick - function (dt, rowId) { return; } - Function called when clicking on empty space inside the Gantti data panel.
The parameter passed to the function is the date/time in milliseconds for the clicked cell, and the ID of the source object (row), if one was provided.
- onRender - $.noop - Function called whenever the chart is (re)rendered
- useCookie - false - indicates whether or not cookies should be used to save and restore the chart's view state (scale, scroll position) between page loads; - jquery.cookie.js needs to be referenced for this to work
- cookieKey - "jquery.fn.gantt" - The prefix used when storing cookies (depends on useCookie being set to true)
- scrollToToday - true - Boolean
+ + useCookie + + false + + indicates if cookies should be used to track the chart's state (scale, scrollposition) between postpacks
+ jquery.cookie.js needs to be referenced for this to work + + + + scrollToToday + + true + + Boolean + + + -

- Source Configuration -

+

+ Source Configuration +

-
-source: [
-    {
-        name: "Example",
-        desc: "Lorem ipsum dolor sit amet.",
-        values: [ ... ]
-        id: 1,
-        cssClass: "redLabel"
-    },
-    ... // more rows
-]
+
+source: [{
+	name: "Example",
+	desc: "Lorem ipsum dolor sit amet.",
+	values: [ ... ]
+}]
 
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- Parameter - - Accepts Type - - Meaning -
- name - - string - - Optional primary label for this row of values; appears in the leftmost column of the row. -
- desc - - string - - Optional secondary label for this row of the Gantt. -
- values - - Array - - Sequence of date ranges for each row of the Gantt. See next table. -
- id - - string or number - - Optional value to be passed as second parameter to onAddClick() callback when triggered. -
- cssClass - - string - - Optional space-separated class names to be applied to this row's labels. -
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ Parameter + + Default + + Accepts Type + + Meaning +
+ name + + null + + String + + Bold value in the left-most column of the gantt row. +
+ desc + + null + + String + + Secondary value in the gantt row. +
+ values + + null + + Array + + Collection of date ranges for gantt items. See next table. +
-

- Value Configuration -

+

+ Value Configuration +

-
-values: [
-    {
-        from: "/Date(1333411200000)/",
-        to: "/Date(1328832000000)/",
-        label: "Example Value",
-        desc: "Something",
-        customClass: "ganttRed",
-        dataObj: foo.bar[i]
-    },
-    ... // more items for the row (though Gantt charts traditionally have only one item per row)
-]
+
+values: [{
+	to: "/Date(1328832000000)/",
+	from: "/Date(1333411200000)/",
+	desc: "Something",
+	label: "Example Value",
+	customClass: "ganttRed",
+	dataObj: foo.bar[i]
+}]
 
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- Parameter - - Accepts Type - - Meaning -
- from - - number (ms), string (see formats) - - Start date/time of the Gantt item. -
- to - - number (ms), string (see formats) - - End date/time of the Gantt item. -
- label - - string - - Optional label/name of the Gantt item. -
- desc - - string - - Optional description of the Gantt item, used as HTML content of hover "hint"). -
- customClass - - string - - Optional space-separated class names to be applied to the Gantt item. -
- dataObj - - Any - - Optional data object that is stored directly on the Gantt item. -
- -
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ Parameter + + Accepts Type + + Meaning +
+ to + + String (Date) + + - +
+ from + + String (Date) + + - +
+ desc + + String + + Text that appears on hover, I think? +
+ label + + String + + Appears on the gantt item. +
+ customClass + + String ("ganttBlue", "ganttGreen", "ganttRed", "ganttOrange", "ganttGray", "MyClass") + + Custom class to be applied to the gantt item. +
+ dataObj + + All + + A data object that is applied directly to the gantt item. +
- - - - - - + + + + + prettyPrint(); + }); + diff --git a/js/dataDays.js b/js/dataDays.js index e11088c..ea12966 100644 --- a/js/dataDays.js +++ b/js/dataDays.js @@ -1,16 +1,12 @@ -[{ "name": " Planning ","desc": "Inception","values": [{"from": "/Date(1320192000000)/", "to": "/Date(1321401600000)/", "desc": "Id: 1
Name: Planning
Date: 2011-11-02 to 2011-11-16", "label": " Planni...", "customClass": "ganttRed"}]}, -{ "name": " Gathering requirements ","desc": "Inception","values": [{"from": "/Date(1321401600000)/", "to": "/Date(1322870400000)/", "desc": "Id: 2
Name: Gathering requirements
Date: 2011-11-16 to 2011-12-03", "label": " Gather...", "customClass": "ganttGreen"}]}, -{ "name": " Determine scope ","desc": "Inception","values": [{"from": "/Date(1322611200000)/", "to": "/Date(1323302400000)/", "desc": "Id: 3
Name: Determine scope
Date: 2011-11-30 to 2011-12-08", "label": " Determ...", "customClass": "ganttOrange"}]}, -{ "name": " Analysis and design ","desc": "Iteration 1","values": [{"from": "/Date(1323302400000)/", "to": "/Date(1324684800000)/", "desc": "Id: 4
Name: Analysis and design
Date: 2011-12-08 to 2011-12-24", "label": " Analys..."}]}, -{ "name": " Implementation ","desc": "Iteration 1","values": [{"from": "/Date(1324857600000)/", "to": "/Date(1326758400000)/", "desc": "Id: 5
Name: Implementation
Date: 2011-12-26 to 2012-01-17", "label": " Implem...", "customClass": "ganttRed"}]}, -{ "name": " Deliver prototype ","desc": "Iteration 1","values": [{"from": "/Date(1326758400000)/", "to": "/Date(1326844800000)/", "desc": "Id: 6
Name: Deliver prototype
Date: 2012-01-17 to 2012-01-18", "label": " Delive...", "customClass": "ganttGreen"}]}, -{ "name": " Testing ","desc": "Iteration 1","values": [{"from": "/Date(1326844800000)/", "to": "/Date(1328659200000)/", "desc": "Id: 7
Name: Testing
Date: 2012-01-18 to 2012-02-08", "label": " Testin...", "customClass": "ganttOrange"}]}, -{ "name": " Review and evaluation ","desc": "Iteration 1","values": [{"from": "/Date(1328659200000)/", "to": "/Date(1328832000000)/", "desc": "Id: 8
Name: Review and evaluation
Date: 2012-02-08 to 2012-02-10", "label": " Review..."}]}, -{ "name": " Analysis and enhancement of design ","desc": "Iteration 2","values": [{"from": "/Date(1328832000000)/", "to": "/Date(1329868800000)/", "desc": "Id: 9
Name: Analysis and enhancement of design
Date: 2012-02-10 to 2012-02-22", "label": " Analys...", "customClass": "ganttRed"}]}, -{ "name": " Implementation (enhancement of prototype)","desc": "Iteration 2","values": [{"from": "/Date(1329868800000)/", "to": "/Date(1331337600000)/", "desc": "Id: 10
Name: Implementation (enhancement of prototype)
Date: 2012-02-22 to 2012-03-10", "label": " Implem...", "customClass": "ganttGreen"}]}, -{ "name": " Deliver prototype ","desc": "Iteration 2","values": [{"from": "/Date(1331510400000)/", "to": "/Date(1331596800000)/", "desc": "Id: 11
Name: Deliver prototype
Date: 2012-03-12 to 2012-03-13", "label": " Delive...", "customClass": "ganttOrange"}]}, -{ "name": " Testing ","desc": "Iteration 2","values": [{"from": "/Date(1331596800000)/", "to": "/Date(1332547200000)/", "desc": "Id: 12
Name: Testing
Date: 2012-03-13 to 2012-03-24", "label": " Testin...", "customClass": "ganttRed"}]}, -{ "name": " Review and evaluation ","desc": "Iteration 2","values": [{"from": "/Date(1332720000000)/", "to": "/Date(1332892800000)/", "desc": "Id: 13
Name: Review and evaluation
Date: 2012-03-26 to 2012-03-28", "label": " Review...", "customClass": "ganttGreen"}]}, -{ "name": " Finalising ","desc": "Finalization","values": [{"from": "/Date(1332892800000)/", "to": "/Date(1333065600000)/", "desc": "Id: 14
Name: Finalising
Date: 2012-03-28 to 2012-03-30", "label": " Finali...", "customClass": "ganttOrnage"}]}, -{ "name": " Deployment ","desc": "Finalization","values": [{"from": "/Date(1333065600000)/", "to": "/Date(1333411200000)/", "desc": "Id: 15
Name: Deployment
Date: 2012-03-30 to 2012-04-03", "label": " Deploy..."}]}, -{ "name": " Project review and evaluation ","desc": "Finalization","values": [{"from": "/Date(1333411200000)/", "to": "/Date(1333584000000)/", "desc": "Id: 16
Name: Project review and evaluation
Date: 2012-04-03 to 2012-04-05", "label": " Projec...", "customClass": "ganttRed"}]}] +[ +{ "name": " Step A ","desc": "→ Step B" ,"values": [{"id": "b0", "from": "/Date(1320182000000)/", "to": "/Date(1320301600000)/", "desc": "Id: 0
Name: Step A", "label": " Step A", "customClass": "ganttRed", "dep": "b1"}]}, +{ "name": " Step B ","desc": "→ step C" ,"values": [{"id": "b1", "from": "/Date(1320601600000)/", "to": "/Date(1320870400000)/", "desc": "Id: 1
Name: Step B", "label": " Step B", "customClass": "ganttOrange", "dep": "b2"}]}, +{ "name": " Step C ","desc": "→ step D" ,"values": [{"id": "b2", "from": "/Date(1321192000000)/", "to": "/Date(1321500400000)/", "desc": "Id: 2
Name: Step C", "label": " Step C", "customClass": "ganttGreen", "dep": "b3"}]}, +{ "name": " Step D ","desc": "→ step E" ,"values": [{"id": "b3", "from": "/Date(1320302400000)/", "to": "/Date(1320551600000)/", "desc": "Id: 3
Name: Step D", "label": " Step D", "dep": "b4"}]}, +{ "name": " Step E ","desc": "—" ,"values": [{"id": "b4", "from": "/Date(1320802400000)/", "to": "/Date(1321994800000)/", "desc": "Id: 4
Name: Step E", "label": " Step E", "customClass": "ganttRed"}]}, +{ "name": " Step F ","desc": "→ step B" ,"values": [{"id": "b5", "from": "/Date(1320192000000)/", "to": "/Date(1320401600000)/", "desc": "Id: 5
Name: Step F", "label": " Step F", "customClass": "ganttOrange", "dep": "b1"}]}, +{ "name": " Step G ","desc": "→ step C" ,"values": [{"id": "b6", "from": "/Date(1320401600000)/", "to": "/Date(1320570400000)/", "desc": "Id: 6
Name: Step G", "label": " Step G", "customClass": "ganttGreen", "dep": "b8"}]}, +{ "name": " Step H ","desc": "→ Step J" ,"values": [{"id": "b7", "from": "/Date(1321192000000)/", "to": "/Date(1321500400000)/", "desc": "Id: 7
Name: Step H", "label": " Step H", "dep": "b9"}]}, +{ "name": " Step I ","desc": "→ Step H" ,"values": [{"id": "b8", "from": "/Date(1320302400000)/", "to": "/Date(1320551600000)/", "desc": "Id: 8
Name: Step I", "label": " Step I", "customClass": "ganttRed", "dep": "b7"}]}, +{ "name": " Step J ","desc": "—" ,"values": [{"id": "b9", "from": "/Date(1320802400000)/", "to": "/Date(1321994800000)/", "desc": "Id: 9
Name: Step J", "label": " Step J", "customClass": "ganttOrange"}]} +] diff --git a/js/jquery.cookie.js b/js/jquery.cookie.js new file mode 100644 index 0000000..f8f852c --- /dev/null +++ b/js/jquery.cookie.js @@ -0,0 +1,96 @@ +/*! + * jQuery Cookie Plugin v1.3.1 + * https://github.com/carhartl/jquery-cookie + * + * Copyright 2013 Klaus Hartl + * Released under the MIT license + */ +(function (factory) { + if (typeof define === 'function' && define.amd) { + // AMD. Register as anonymous module. + define(['jquery'], factory); + } else { + // Browser globals. + factory(jQuery); + } +}(function ($) { + + var pluses = /\+/g; + + function decode(s) { + if (config.raw) { + return s; + } + return decodeURIComponent(s.replace(pluses, ' ')); + } + + function decodeAndParse(s) { + if (s.indexOf('"') === 0) { + // This is a quoted cookie as according to RFC2068, unescape... + s = s.slice(1, -1).replace(/\\"/g, '"').replace(/\\\\/g, '\\'); + } + + s = decode(s); + + try { + return config.json ? JSON.parse(s) : s; + } catch(e) {} + } + + var config = $.cookie = function (key, value, options) { + + // Write + if (value !== undefined) { + options = $.extend({}, config.defaults, options); + + if (typeof options.expires === 'number') { + var days = options.expires, t = options.expires = new Date(); + t.setDate(t.getDate() + days); + } + + value = config.json ? JSON.stringify(value) : String(value); + + return (document.cookie = [ + config.raw ? key : encodeURIComponent(key), + '=', + config.raw ? value : encodeURIComponent(value), + options.expires ? '; expires=' + options.expires.toUTCString() : '', // use expires attribute, max-age is not supported by IE + options.path ? '; path=' + options.path : '', + options.domain ? '; domain=' + options.domain : '', + options.secure ? '; secure' : '' + ].join('')); + } + + // Read + var cookies = document.cookie.split('; '); + var result = key ? undefined : {}; + for (var i = 0, l = cookies.length; i < l; i++) { + var parts = cookies[i].split('='); + var name = decode(parts.shift()); + var cookie = parts.join('='); + + if (key && key === name) { + result = decodeAndParse(cookie); + break; + } + + if (!key) { + result[name] = decodeAndParse(cookie); + } + } + + return result; + }; + + config.defaults = {}; + + $.removeCookie = function (key, options) { + if ($.cookie(key) !== undefined) { + // Must not alter options, thus extending a fresh object... + $.cookie(key, '', $.extend({}, options, { expires: -1 })); + return true; + } + return false; + }; + +})); diff --git a/js/jquery.fn.gantt.js b/js/jquery.fn.gantt.js index a017958..439320a 100644 --- a/js/jquery.fn.gantt.js +++ b/js/jquery.fn.gantt.js @@ -1,1698 +1,1725 @@ -/** - * jQuery Gantt Chart - * - * @see http://taitems.github.io/jQuery.Gantt/ - * @license MIT - */ -/*jshint camelcase:true, freeze:true, jquery:true */ -(function ($, undefined) { - "use strict"; - - // 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. - $.extend($.expr[":"], { - findday: function (a, i, m) { - var cd = new Date(parseInt(m[3], 10)); - var id = $(a).attr("id") || ""; - var si = id.indexOf("-") + 1; - var ed = new Date(parseInt(id.substring(si, id.length), 10)); - cd = new Date(cd.getFullYear(), cd.getMonth(), cd.getDate()); - ed = new Date(ed.getFullYear(), ed.getMonth(), ed.getDate()); - return cd.getTime() === ed.getTime(); - } - }); - // custom selector `:findweek` used to match on specified week in ms. - $.extend($.expr[":"], { - findweek: function (a, i, m) { - var cd = new Date(parseInt(m[3], 10)); - var id = $(a).attr("id") || ""; - var si = id.indexOf("-") + 1; - cd = cd.getFullYear() + "-" + cd.getDayForWeek().getWeekOfYear(); - var ed = id.substring(si, id.length); - return cd === ed; - } - }); - // custom selector `:findmonth` used to match on specified month in ms. - $.extend($.expr[":"], { - findmonth: function (a, i, m) { - var cd = new Date(parseInt(m[3], 10)); - cd = cd.getFullYear() + "-" + cd.getMonth(); - var id = $(a).attr("id") || ""; - var si = id.indexOf("-") + 1; - var ed = id.substring(si, id.length); - return cd === ed; - } - }); - - // 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.getDayForWeek().getWeekOfYear(); - var m = this.getMonth(); - if (m === 11 && w === 1) { - 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 fd = new Date(this.getFullYear(), 0, 0); - var sd = new Date(this.getFullYear(), this.getMonth(), this.getDate()); - return Math.ceil((sd - fd) / 86400000); - }; - - // `getWeekOfYear` returns the week number for the year - Date.prototype.getWeekOfYear = function () { - var ys = new Date(this.getFullYear(), 0, 1); - var sd = new Date(this.getFullYear(), this.getMonth(), this.getDate()); - if (ys.getDay() > 3) { - ys = new Date(sd.getFullYear(), 0, (7 - ys.getDay())); - } - var daysCount = sd.getDayOfYear() - ys.getDayOfYear(); - return Math.ceil(daysCount / 7); - - }; - - // `getDayForWeek` returns the Date object for the starting date of - // the week # for the year - Date.prototype.getDayForWeek = function () { - var df = new Date(this.valueOf()); - df.setDate(df.getDate() - df.getDay()); - var dt = new Date(this.valueOf()); - dt.setDate(dt.getDate() + (6 - dt.getDay())); - if ((df.getMonth() === dt.getMonth()) || (df.getMonth() !== dt.getMonth() && dt.getDate() >= 4)) { - return new Date(dt.setDate(dt.getDate() - 3)); - } else { - return new Date(df.setDate(df.getDate() + 3)); - } - }; - - // 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) { - - var scales = ["hours", "days", "weeks", "months"]; - //Default settings - var settings = { - source: [], - cookieKey: "jquery.fn.gantt", - itemsPerPage: 7, - dow: ["S", "M", "T", "W", "T", "F", "S"], - months: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"], - navigate: "buttons", - scale: "days", - scrollToToday: true, - useCookie: false, - maxScale: "months", - minScale: "hours", - waitText: "Please wait...", - 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); - - - /* core.render(element); */ - core.waitToggle(element, true, function () { core.render(element); }); - }, - - // **Render the grid** - render: function (element) { - var content = $('
'); - var $leftPanel = core.leftPanel(element); - content.append($leftPanel); - var $rightPanel = core.rightPanel(element, $leftPanel); - var mLeft, hPos; - - content.append($rightPanel); - content.append(core.navigation(element)); - - var $dataPanel = $rightPanel.find(".dataPanel"); - - element.gantt = $('
').append(content); - - $(element).empty().append(element.gantt); - - element.scrollNavigation.panelMargin = parseInt($dataPanel.css("margin-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) { - mLeft = ($dataPanel.width() - $rightPanel.width()); - hPos = mLeft * element.hPosition / element.scaleOldWidth; - element.hPosition = hPos > 0 ? 0 : hPos; - element.scaleOldWidth = null; - } - $dataPanel.css({ "margin-left": element.hPosition }); - element.scrollNavigation.panelMargin = element.hPosition; - } - core.repositionLabel(element); - } - - $dataPanel.css({ height: $leftPanel.height() }); - core.waitToggle(element, false); - settings.onRender(); - }, - - // Create and return the left panel with labels - leftPanel: function (element) { - /* Left panel */ - var ganttLeftPanel = $('
') - .append($('
') - .css("height", tools.getCellSize() * element.headerRows) - .css("width", "100%")); - - var entries = []; - $.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('
'); - entries.push('' + (entry.name || '') + ''); - entries.push('
'); - - if (entry.desc) { - entries.push('
'); - entries.push('' + entry.desc + ''); - entries.push('
'); - } - - } - }); - ganttLeftPanel.append(entries.join("")); - return ganttLeftPanel; - }, - - // 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 daysInYear = 0; - - var monthArr = []; - var daysInMonth = 0; - - var dayArr = []; - var hoursInDay = 0; - - var dowArr = []; - var horArr = []; - - var today = new Date(); - today.setHours(0, 0, 0, 0); - - // reused variables - var i, len; - var year, month, day; - var rday, dayClass; - var dataPanel; - - // Setup the headings based on the chosen `settings.scale` - switch (settings.scale) { - // **Hours** - case "hours": - range = tools.parseTimeRange(element.dateStart, element.dateEnd, element.scaleStep); - - 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; - daysInYear = 0; - } - daysInYear++; - - - // Fill months - var rm = rday.getMonth(); - if (rm !== month) { - monthArr.push( - '
' + - settings.months[month] + - '
'); - - month = rm; - daysInMonth = 0; - } - daysInMonth++; - - - // Fill days & hours - - var rgetDay = rday.getDay(); - var getDay = day.getDay(); - dayClass = dowClass[rgetDay]; - if (tools.isHoliday(rday)) { - dayClass = "holiday"; - } - if (rgetDay !== getDay) { - var dayClass2 = (today - day === 0) ? "today" : tools.isHoliday( day.getTime() ) ? "holiday" : dowClass[getDay]; - - dayArr.push( - '
' + - '
' + day.getDate() + '
'); - dowArr.push( - '
' + - '
' + settings.dow[getDay] + '
'); - - day = rday; - hoursInDay = 0; - } - hoursInDay++; - - horArr.push( - '
' + - rday.getHours() + - '
'); - } - - - // Last year - yearArr.push( - '
' + - year + - '
'); - - // Last month - monthArr.push( - '
' + - settings.months[month] + - '
'); - - dayClass = dowClass[day.getDay()]; - - if ( tools.isHoliday(day) ) { - dayClass = "holiday"; - } - - dayArr.push( - '
' + - '
' + day.getDate() + '
'); - - dowArr.push( - '
' + - '
' + settings.dow[day.getDay()] + '
'); - - dataPanel = core.dataPanel(element, range.length * tools.getCellSize()); - - - // Append panel elements - dataPanel.append( - $('
').html(yearArr.join("")), - $('
').html(monthArr.join("")), - $('
').html(dayArr.join("")), - $('
').html(dowArr.join("")), - $('
').html(horArr.join("")) - ); - - break; - - // **Weeks** - case "weeks": - range = tools.parseWeeksRange(element.dateStart, element.dateEnd); - yearArr = []; - monthArr = []; - 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 - if (rday.getFullYear() !== year) { - yearArr.push( - '
' + - year + - '
'); - year = rday.getFullYear(); - daysInYear = 0; - } - daysInYear++; - - // Fill months - if (rday.getMonth() !== month) { - monthArr.push( - '
' + - settings.months[month] + - '
'); - month = rday.getMonth(); - daysInMonth = 0; - } - daysInMonth++; - - // Fill weeks - dayArr.push( - '
' + - '
' + rday.getWeekOfYear() + '
'); - } - - - // Last year - yearArr.push( - '
' + - year + - '
'); - - // Last month - monthArr.push( - '
' + - settings.months[month] + - '
'); - - dataPanel = core.dataPanel(element, range.length * tools.getCellSize()); - - dataPanel.append(yearArr.join("") + monthArr.join("") + dayArr.join("") + dowArr.join("")); - - break; - - // **Months** - case 'months': - range = tools.parseMonthsRange(element.dateStart, element.dateEnd); - - 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 - if (rday.getFullYear() !== year) { - yearArr.push( - '
' + - year + - '
'); - year = rday.getFullYear(); - daysInYear = 0; - } - daysInYear++; - monthArr.push('
' + (1 + rday.getMonth()) + '
'); - } - - - // Last year - yearArr.push( - '
' + - year + - '
'); - - // Last month - monthArr.push( - '
' + - settings.months[month] + - '
'); - - dataPanel = core.dataPanel(element, range.length * tools.getCellSize()); - - // Append panel elements - dataPanel.append( - $('
').html(yearArr.join("")), - $('
').html(monthArr.join("")), - $('
').html(dayArr.join("")), - $('
').html(dowArr.join("")) - ); - - break; - - // **Days (default)** - default: - range = tools.parseDateRange(element.dateStart, element.dateEnd); - - var dateBefore = ktkGetNextDate(range[0], -1); - year = dateBefore.getFullYear(); - month = dateBefore.getMonth(); - //day = dateBefore; // <- never used? - - for (i = 0, len = range.length; i < len; i++) { - rday = range[i]; - - // Fill years - if (rday.getFullYear() !== year) { - yearArr.push( - '
' + - year + - '
'); - year = rday.getFullYear(); - daysInYear = 0; - } - daysInYear++; - - // Fill months - if (rday.getMonth() !== month) { - monthArr.push( - '
' + - settings.months[month] + - '
'); - month = rday.getMonth(); - daysInMonth = 0; - } - daysInMonth++; - - day = rday.getDay(); - dayClass = dowClass[day]; - if ( tools.isHoliday(rday) ) { - dayClass = "holiday"; - } - - dayArr.push( - '
' + - '
' + rday.getDate() + '
'); - dowArr.push( - '
' + - '
' + settings.dow[day] + '
'); - } //for - - // Last year - yearArr.push( - '
' + - year + - '
'); - - // Last month - monthArr.push( - '
' + - settings.months[month] + - '
'); - - dataPanel = core.dataPanel(element, range.length * tools.getCellSize()); - - - // Append panel elements - dataPanel.append( - $('
').html(yearArr.join("")), - $('
').html(monthArr.join("")), - $('
').html(dayArr.join("")), - $('
').html(dowArr.join("")) - ); - } - - return $('
').append(dataPanel); - }, - - // **Navigation** - navigation: function (element) { - var ganttNavigate = null; - // Scrolling navigation is provided by setting - // `settings.navigate='scroll'` - if (settings.navigate === "scroll") { - ganttNavigate = $('