diff --git a/HISTORY.md b/HISTORY.md index 53f0fe68..2b83e5a4 100644 --- a/HISTORY.md +++ b/HISTORY.md @@ -2,7 +2,7 @@ http://visjs.org -## not yet released, version 4.8.1-SNAPSHOT +## 2015-09-07, version 4.8.1 ### Network diff --git a/bower.json b/bower.json index 6fe859f2..9f0e5c63 100644 --- a/bower.json +++ b/bower.json @@ -1,6 +1,6 @@ { "name": "vis", - "version": "4.8.1-SNAPSHOT", + "version": "4.8.1", "main": ["dist/vis.min.js", "dist/vis.min.css"], "description": "A dynamic, browser-based visualization library.", "homepage": "http://visjs.org/", diff --git a/dist/vis.js b/dist/vis.js index 50d54588..e91f4756 100644 --- a/dist/vis.js +++ b/dist/vis.js @@ -4,8 +4,8 @@ * * A dynamic, browser-based visualization library. * - * @version 4.8.1-SNAPSHOT - * @date 2015-09-06 + * @version 4.8.1 + * @date 2015-09-07 * * @license * Copyright (C) 2011-2015 Almende B.V, http://almende.com @@ -29,7 +29,7 @@ if(typeof exports === 'object' && typeof module === 'object') module.exports = factory(); else if(typeof define === 'function' && define.amd) - define(factory); + define([], factory); else if(typeof exports === 'object') exports["vis"] = factory(); else @@ -97,8 +97,8 @@ return /******/ (function(modules) { // webpackBootstrap exports.graph3d = { Camera: __webpack_require__(15), Filter: __webpack_require__(16), - Point2d: __webpack_require__(12), - Point3d: __webpack_require__(14), + Point2d: __webpack_require__(14), + Point3d: __webpack_require__(13), Slider: __webpack_require__(17), StepNumber: __webpack_require__(18) }; @@ -110,16 +110,16 @@ return /******/ (function(modules) { // webpackBootstrap DateUtil: __webpack_require__(27), DataStep: __webpack_require__(52), Range: __webpack_require__(24), - stack: __webpack_require__(31), - TimeStep: __webpack_require__(34), + stack: __webpack_require__(32), + TimeStep: __webpack_require__(30), components: { items: { - Item: __webpack_require__(33), + Item: __webpack_require__(34), BackgroundItem: __webpack_require__(38), BoxItem: __webpack_require__(36), PointItem: __webpack_require__(37), - RangeItem: __webpack_require__(32) + RangeItem: __webpack_require__(33) }, Component: __webpack_require__(26), @@ -127,7 +127,7 @@ return /******/ (function(modules) { // webpackBootstrap CustomTime: __webpack_require__(42), DataAxis: __webpack_require__(51), GraphGroup: __webpack_require__(53), - Group: __webpack_require__(30), + Group: __webpack_require__(31), BackgroundGroup: __webpack_require__(35), ItemSet: __webpack_require__(29), Legend: __webpack_require__(57), @@ -551,11 +551,11 @@ return /******/ (function(modules) { // webpackBootstrap // object is an ASP date return new Date(Number(match[1])); // parse number } else { - return moment(object).toDate(); // parse string - } - } else { - throw new Error('Cannot convert object of type ' + exports.getType(object) + ' to type Date'); + return moment(object).toDate(); // parse string } + } else { + throw new Error('Cannot convert object of type ' + exports.getType(object) + ' to type Date'); + } case 'Moment': if (exports.isNumber(object)) { @@ -572,11 +572,11 @@ return /******/ (function(modules) { // webpackBootstrap // object is an ASP date return moment(Number(match[1])); // parse number } else { - return moment(object); // parse string - } - } else { - throw new Error('Cannot convert object of type ' + exports.getType(object) + ' to type Date'); + return moment(object); // parse string } + } else { + throw new Error('Cannot convert object of type ' + exports.getType(object) + ' to type Date'); + } case 'ISODate': if (exports.isNumber(object)) { @@ -591,11 +591,11 @@ return /******/ (function(modules) { // webpackBootstrap // object is an ASP date return new Date(Number(match[1])).toISOString(); // parse number } else { - return new Date(object).toISOString(); // parse string - } - } else { - throw new Error('Cannot convert object of type ' + exports.getType(object) + ' to type ISODate'); + return new Date(object).toISOString(); // parse string } + } else { + throw new Error('Cannot convert object of type ' + exports.getType(object) + ' to type ISODate'); + } case 'ASPDate': if (exports.isNumber(object)) { @@ -609,8 +609,8 @@ return /******/ (function(modules) { // webpackBootstrap // object is an ASP date value = new Date(Number(match[1])).valueOf(); // parse number } else { - value = new Date(object).valueOf(); // parse string - } + value = new Date(object).valueOf(); // parse string + } return '/Date(' + value + ')/'; } else { throw new Error('Cannot convert object of type ' + exports.getType(object) + ' to type ASPDate'); @@ -842,13 +842,13 @@ return /******/ (function(modules) { // webpackBootstrap if (element.addEventListener) { if (useCapture === undefined) useCapture = false; - if (action === "mousewheel" && navigator.userAgent.indexOf("Firefox") >= 0) { - action = "DOMMouseScroll"; // For Firefox + if (action === 'mousewheel' && navigator.userAgent.indexOf('Firefox') >= 0) { + action = 'DOMMouseScroll'; // For Firefox } element.addEventListener(action, listener, useCapture); } else { - element.attachEvent("on" + action, listener); // IE browsers + element.attachEvent('on' + action, listener); // IE browsers } }; @@ -864,14 +864,14 @@ return /******/ (function(modules) { // webpackBootstrap // non-IE browsers if (useCapture === undefined) useCapture = false; - if (action === "mousewheel" && navigator.userAgent.indexOf("Firefox") >= 0) { - action = "DOMMouseScroll"; // For Firefox + if (action === 'mousewheel' && navigator.userAgent.indexOf('Firefox') >= 0) { + action = 'DOMMouseScroll'; // For Firefox } element.removeEventListener(action, listener, useCapture); } else { // IE browsers - element.detachEvent("on" + action, listener); + element.detachEvent('on' + action, listener); } }; @@ -884,8 +884,8 @@ return /******/ (function(modules) { // webpackBootstrap if (event.preventDefault) { event.preventDefault(); // non-IE browsers } else { - event.returnValue = false; // IE browsers - } + event.returnValue = false; // IE browsers + } }; /** @@ -1050,17 +1050,17 @@ return /******/ (function(modules) { // webpackBootstrap * @returns {*} */ exports.overrideOpacity = function (color, opacity) { - if (color.indexOf("rgba") != -1) { + if (color.indexOf('rgba') != -1) { return color; - } else if (color.indexOf("rgb") != -1) { - var rgb = color.substr(color.indexOf("(") + 1).replace(")", "").split(","); - return "rgba(" + rgb[0] + "," + rgb[1] + "," + rgb[2] + "," + opacity + ")"; + } else if (color.indexOf('rgb') != -1) { + var rgb = color.substr(color.indexOf('(') + 1).replace(')', '').split(','); + return 'rgba(' + rgb[0] + ',' + rgb[1] + ',' + rgb[2] + ',' + opacity + ')'; } else { var rgb = exports.hexToRGB(color); if (rgb == null) { return color; } else { - return "rgba(" + rgb.r + "," + rgb.g + "," + rgb.b + "," + opacity + ")"; + return 'rgba(' + rgb.r + ',' + rgb.g + ',' + rgb.b + ',' + opacity + ')'; } } }; @@ -1074,7 +1074,7 @@ return /******/ (function(modules) { // webpackBootstrap * @constructor */ exports.RGBToHex = function (red, green, blue) { - return "#" + ((1 << 24) + (red << 16) + (green << 8) + blue).toString(16).slice(1); + return '#' + ((1 << 24) + (red << 16) + (green << 8) + blue).toString(16).slice(1); }; /** @@ -1290,12 +1290,12 @@ return /******/ (function(modules) { // webpackBootstrap }; exports.isValidRGB = function (rgb) { - rgb = rgb.replace(" ", ""); + rgb = rgb.replace(' ', ''); var isOk = /rgb\((\d{1,3}),(\d{1,3}),(\d{1,3})\)/i.test(rgb); return isOk; }; exports.isValidRGBA = function (rgba) { - rgba = rgba.replace(" ", ""); + rgba = rgba.replace(' ', ''); var isOk = /rgba\((\d{1,3}),(\d{1,3}),(\d{1,3}),(.{1,3})\)/i.test(rgba); return isOk; }; @@ -1308,11 +1308,11 @@ return /******/ (function(modules) { // webpackBootstrap * @returns {*} */ exports.selectiveBridgeObject = function (fields, referenceObject) { - if (typeof referenceObject == "object") { + if (typeof referenceObject == 'object') { var objectTo = Object.create(referenceObject); for (var i = 0; i < fields.length; i++) { if (referenceObject.hasOwnProperty(fields[i])) { - if (typeof referenceObject[fields[i]] == "object") { + if (typeof referenceObject[fields[i]] == 'object') { objectTo[fields[i]] = exports.bridgeObject(referenceObject[fields[i]]); } } @@ -1331,11 +1331,11 @@ return /******/ (function(modules) { // webpackBootstrap * @returns {*} */ exports.bridgeObject = function (referenceObject) { - if (typeof referenceObject == "object") { + if (typeof referenceObject == 'object') { var objectTo = Object.create(referenceObject); for (var i in referenceObject) { if (referenceObject.hasOwnProperty(i)) { - if (typeof referenceObject[i] == "object") { + if (typeof referenceObject[i] == 'object') { objectTo[i] = exports.bridgeObject(referenceObject[i]); } } @@ -1547,13 +1547,13 @@ return /******/ (function(modules) { // webpackBootstrap /***/ function(module, exports, __webpack_require__) { /* WEBPACK VAR INJECTION */(function(module) {//! moment.js - //! version : 2.10.3 + //! version : 2.10.6 //! authors : Tim Wood, Iskren Chernev, Moment.js contributors //! license : MIT //! momentjs.com (function (global, factory) { - true ? module.exports = factory() : + true ? module.exports = factory() : typeof define === 'function' && define.amd ? define(factory) : global.moment = factory() }(this, function () { 'use strict'; @@ -1642,6 +1642,7 @@ return /******/ (function(modules) { // webpackBootstrap flags.overflow < 0 && !flags.empty && !flags.invalidMonth && + !flags.invalidWeekday && !flags.nullInput && !flags.invalidFormat && !flags.userInvalidated; @@ -1722,7 +1723,7 @@ return /******/ (function(modules) { // webpackBootstrap // Moment prototype object function Moment(config) { copyConfig(this, config); - this._d = new Date(+config._d); + this._d = new Date(config._d != null ? config._d.getTime() : NaN); // Prevent infinite loop in case updateOffset creates new moment // objects. if (updateInProgress === false) { @@ -1736,16 +1737,20 @@ return /******/ (function(modules) { // webpackBootstrap return obj instanceof Moment || (obj != null && obj._isAMomentObject != null); } + function absFloor (number) { + if (number < 0) { + return Math.ceil(number); + } else { + return Math.floor(number); + } + } + function toInt(argumentForCoercion) { var coercedNumber = +argumentForCoercion, value = 0; if (coercedNumber !== 0 && isFinite(coercedNumber)) { - if (coercedNumber >= 0) { - value = Math.floor(coercedNumber); - } else { - value = Math.ceil(coercedNumber); - } + value = absFloor(coercedNumber); } return value; @@ -1843,9 +1848,7 @@ return /******/ (function(modules) { // webpackBootstrap function defineLocale (name, values) { if (values !== null) { values.abbr = name; - if (!locales[name]) { - locales[name] = new Locale(); - } + locales[name] = locales[name] || new Locale(); locales[name].set(values); // backwards compat for now: also set the locale @@ -1949,16 +1952,14 @@ return /******/ (function(modules) { // webpackBootstrap } function zeroFill(number, targetLength, forceSign) { - var output = '' + Math.abs(number), + var absNumber = '' + Math.abs(number), + zerosToFill = targetLength - absNumber.length, sign = number >= 0; - - while (output.length < targetLength) { - output = '0' + output; - } - return (sign ? (forceSign ? '+' : '') : '-') + output; + return (sign ? (forceSign ? '+' : '') : '-') + + Math.pow(10, Math.max(0, zerosToFill)).toString().substr(1) + absNumber; } - var formattingTokens = /(\[[^\[]*\])|(\\)?(Mo|MM?M?M?|Do|DDDo|DD?D?D?|ddd?d?|do?|w[o|w]?|W[o|W]?|Q|YYYYYY|YYYYY|YYYY|YY|gg(ggg?)?|GG(GGG?)?|e|E|a|A|hh?|HH?|mm?|ss?|S{1,4}|x|X|zz?|ZZ?|.)/g; + var formattingTokens = /(\[[^\[]*\])|(\\)?(Mo|MM?M?M?|Do|DDDo|DD?D?D?|ddd?d?|do?|w[o|w]?|W[o|W]?|Q|YYYYYY|YYYYY|YYYY|YY|gg(ggg?)?|GG(GGG?)?|e|E|a|A|hh?|HH?|mm?|ss?|S{1,9}|x|X|zz?|ZZ?|.)/g; var localFormattingTokens = /(\[[^\[]*\])|(\\)?(LTS|LT|LL?L?L?|l{1,4})/g; @@ -2026,10 +2027,7 @@ return /******/ (function(modules) { // webpackBootstrap } format = expandFormat(format, m.localeData()); - - if (!formatFunctions[format]) { - formatFunctions[format] = makeFormatFunction(format); - } + formatFunctions[format] = formatFunctions[format] || makeFormatFunction(format); return formatFunctions[format](m); } @@ -2073,8 +2071,15 @@ return /******/ (function(modules) { // webpackBootstrap var regexes = {}; + function isFunction (sth) { + // https://github.com/moment/moment/issues/2325 + return typeof sth === 'function' && + Object.prototype.toString.call(sth) === '[object Function]'; + } + + function addRegexToken (token, regex, strictRegex) { - regexes[token] = typeof regex === 'function' ? regex : function (isStrict) { + regexes[token] = isFunction(regex) ? regex : function (isStrict) { return (isStrict && strictRegex) ? strictRegex : regex; }; } @@ -2282,12 +2287,11 @@ return /******/ (function(modules) { // webpackBootstrap } function deprecate(msg, fn) { - var firstTime = true, - msgWithStack = msg + '\n' + (new Error()).stack; + var firstTime = true; return extend(function () { if (firstTime) { - warn(msgWithStack); + warn(msg + '\n' + (new Error()).stack); firstTime = false; } return fn.apply(this, arguments); @@ -2335,14 +2339,14 @@ return /******/ (function(modules) { // webpackBootstrap getParsingFlags(config).iso = true; for (i = 0, l = isoDates.length; i < l; i++) { if (isoDates[i][1].exec(string)) { - // match[5] should be 'T' or undefined - config._f = isoDates[i][0] + (match[6] || ' '); + config._f = isoDates[i][0]; break; } } for (i = 0, l = isoTimes.length; i < l; i++) { if (isoTimes[i][1].exec(string)) { - config._f += isoTimes[i][0]; + // match[6] should be 'T' or space + config._f += (match[6] || ' ') + isoTimes[i][0]; break; } } @@ -2421,7 +2425,10 @@ return /******/ (function(modules) { // webpackBootstrap addRegexToken('YYYYY', match1to6, match6); addRegexToken('YYYYYY', match1to6, match6); - addParseToken(['YYYY', 'YYYYY', 'YYYYYY'], YEAR); + addParseToken(['YYYYY', 'YYYYYY'], YEAR); + addParseToken('YYYY', function (input, array) { + array[YEAR] = input.length === 2 ? utils_hooks__hooks.parseTwoDigitYear(input) : toInt(input); + }); addParseToken('YY', function (input, array) { array[YEAR] = utils_hooks__hooks.parseTwoDigitYear(input); }); @@ -2548,18 +2555,18 @@ return /******/ (function(modules) { // webpackBootstrap //http://en.wikipedia.org/wiki/ISO_week_date#Calculating_a_date_given_the_year.2C_week_number_and_weekday function dayOfYearFromWeeks(year, week, weekday, firstDayOfWeekOfYear, firstDayOfWeek) { - var d = createUTCDate(year, 0, 1).getUTCDay(); - var daysToAdd; - var dayOfYear; + var week1Jan = 6 + firstDayOfWeek - firstDayOfWeekOfYear, janX = createUTCDate(year, 0, 1 + week1Jan), d = janX.getUTCDay(), dayOfYear; + if (d < firstDayOfWeek) { + d += 7; + } - d = d === 0 ? 7 : d; - weekday = weekday != null ? weekday : firstDayOfWeek; - daysToAdd = firstDayOfWeek - d + (d > firstDayOfWeekOfYear ? 7 : 0) - (d < firstDayOfWeek ? 7 : 0); - dayOfYear = 7 * (week - 1) + (weekday - firstDayOfWeek) + daysToAdd + 1; + weekday = weekday != null ? 1 * weekday : firstDayOfWeek; + + dayOfYear = 1 + week1Jan + 7 * (week - 1) - d + weekday; return { - year : dayOfYear > 0 ? year : year - 1, - dayOfYear : dayOfYear > 0 ? dayOfYear : daysInYear(year - 1) + dayOfYear + year: dayOfYear > 0 ? year : year - 1, + dayOfYear: dayOfYear > 0 ? dayOfYear : daysInYear(year - 1) + dayOfYear }; } @@ -2845,9 +2852,19 @@ return /******/ (function(modules) { // webpackBootstrap } function createFromConfig (config) { + var res = new Moment(checkOverflow(prepareConfig(config))); + if (res._nextDay) { + // Adding is smart enough around DST + res.add(1, 'd'); + res._nextDay = undefined; + } + + return res; + } + + function prepareConfig (config) { var input = config._i, - format = config._f, - res; + format = config._f; config._locale = config._locale || locale_locales__getLocale(config._l); @@ -2871,14 +2888,7 @@ return /******/ (function(modules) { // webpackBootstrap configFromInput(config); } - res = new Moment(checkOverflow(config)); - if (res._nextDay) { - // Adding is smart enough around DST - res.add(1, 'd'); - res._nextDay = undefined; - } - - return res; + return config; } function configFromInput(config) { @@ -2958,7 +2968,7 @@ return /******/ (function(modules) { // webpackBootstrap } res = moments[0]; for (i = 1; i < moments.length; ++i) { - if (moments[i][fn](res)) { + if (!moments[i].isValid() || moments[i][fn](res)) { res = moments[i]; } } @@ -3070,7 +3080,6 @@ return /******/ (function(modules) { // webpackBootstrap } else { return local__createLocal(input).local(); } - return model._isUTC ? local__createLocal(input).zone(model._offset || 0) : local__createLocal(input).local(); } function getDateOffset (m) { @@ -3170,12 +3179,7 @@ return /******/ (function(modules) { // webpackBootstrap } function hasAlignedHourOffset (input) { - if (!input) { - input = 0; - } - else { - input = local__createLocal(input).utcOffset(); - } + input = input ? local__createLocal(input).utcOffset() : 0; return (this.utcOffset() - input) % 60 === 0; } @@ -3188,12 +3192,24 @@ return /******/ (function(modules) { // webpackBootstrap } function isDaylightSavingTimeShifted () { - if (this._a) { - var other = this._isUTC ? create_utc__createUTC(this._a) : local__createLocal(this._a); - return this.isValid() && compareArrays(this._a, other.toArray()) > 0; + if (typeof this._isDSTShifted !== 'undefined') { + return this._isDSTShifted; } - return false; + var c = {}; + + copyConfig(c, this); + c = prepareConfig(c); + + if (c._a) { + var other = c._isUTC ? create_utc__createUTC(c._a) : local__createLocal(c._a); + this._isDSTShifted = this.isValid() && + compareArrays(c._a, other.toArray()) > 0; + } else { + this._isDSTShifted = false; + } + + return this._isDSTShifted; } function isLocal () { @@ -3353,7 +3369,7 @@ return /******/ (function(modules) { // webpackBootstrap var add_subtract__add = createAdder(1, 'add'); var add_subtract__subtract = createAdder(-1, 'subtract'); - function moment_calendar__calendar (time) { + function moment_calendar__calendar (time, formats) { // We want to compare the start of today, vs this. // Getting start-of-today depends on whether we're local/utc/offset or not. var now = time || local__createLocal(), @@ -3365,7 +3381,7 @@ return /******/ (function(modules) { // webpackBootstrap diff < 1 ? 'sameDay' : diff < 2 ? 'nextDay' : diff < 7 ? 'nextWeek' : 'sameElse'; - return this.format(this.localeData().calendar(format, this, local__createLocal(now))); + return this.format(formats && formats[format] || this.localeData().calendar(format, this, local__createLocal(now))); } function clone () { @@ -3412,14 +3428,6 @@ return /******/ (function(modules) { // webpackBootstrap } } - function absFloor (number) { - if (number < 0) { - return Math.ceil(number); - } else { - return Math.floor(number); - } - } - function diff (input, units, asFloat) { var that = cloneWithOffset(input, this), zoneDelta = (that.utcOffset() - this.utcOffset()) * 6e4, @@ -3610,6 +3618,19 @@ return /******/ (function(modules) { // webpackBootstrap return [m.year(), m.month(), m.date(), m.hour(), m.minute(), m.second(), m.millisecond()]; } + function toObject () { + var m = this; + return { + years: m.year(), + months: m.month(), + date: m.date(), + hours: m.hours(), + minutes: m.minutes(), + seconds: m.seconds(), + milliseconds: m.milliseconds() + }; + } + function moment_valid__isValid () { return valid__isValid(this); } @@ -3781,18 +3802,20 @@ return /******/ (function(modules) { // webpackBootstrap // HELPERS function parseWeekday(input, locale) { - if (typeof input === 'string') { - if (!isNaN(input)) { - input = parseInt(input, 10); - } - else { - input = locale.weekdaysParse(input); - if (typeof input !== 'number') { - return null; - } - } + if (typeof input !== 'string') { + return input; + } + + if (!isNaN(input)) { + return parseInt(input, 10); + } + + input = locale.weekdaysParse(input); + if (typeof input === 'number') { + return input; } - return input; + + return null; } // LOCALES @@ -3815,9 +3838,7 @@ return /******/ (function(modules) { // webpackBootstrap function localeWeekdaysParse (weekdayName) { var i, mom, regex; - if (!this._weekdaysParse) { - this._weekdaysParse = []; - } + this._weekdaysParse = this._weekdaysParse || []; for (i = 0; i < 7; i++) { // make the regex if we don't have it already @@ -3964,12 +3985,26 @@ return /******/ (function(modules) { // webpackBootstrap return ~~(this.millisecond() / 10); }); - function millisecond__milliseconds (token) { - addFormatToken(0, [token, 3], 0, 'millisecond'); - } + addFormatToken(0, ['SSS', 3], 0, 'millisecond'); + addFormatToken(0, ['SSSS', 4], 0, function () { + return this.millisecond() * 10; + }); + addFormatToken(0, ['SSSSS', 5], 0, function () { + return this.millisecond() * 100; + }); + addFormatToken(0, ['SSSSSS', 6], 0, function () { + return this.millisecond() * 1000; + }); + addFormatToken(0, ['SSSSSSS', 7], 0, function () { + return this.millisecond() * 10000; + }); + addFormatToken(0, ['SSSSSSSS', 8], 0, function () { + return this.millisecond() * 100000; + }); + addFormatToken(0, ['SSSSSSSSS', 9], 0, function () { + return this.millisecond() * 1000000; + }); - millisecond__milliseconds('SSS'); - millisecond__milliseconds('SSSS'); // ALIASES @@ -3980,11 +4015,19 @@ return /******/ (function(modules) { // webpackBootstrap addRegexToken('S', match1to3, match1); addRegexToken('SS', match1to3, match2); addRegexToken('SSS', match1to3, match3); - addRegexToken('SSSS', matchUnsigned); - addParseToken(['S', 'SS', 'SSS', 'SSSS'], function (input, array) { + + var token; + for (token = 'SSSS'; token.length <= 9; token += 'S') { + addRegexToken(token, matchUnsigned); + } + + function parseMs(input, array) { array[MILLISECOND] = toInt(('0.' + input) * 1000); - }); + } + for (token = 'S'; token.length <= 9; token += 'S') { + addParseToken(token, parseMs); + } // MOMENTS var getSetMillisecond = makeGetSet('Milliseconds', false); @@ -4031,6 +4074,7 @@ return /******/ (function(modules) { // webpackBootstrap momentPrototype__proto.startOf = startOf; momentPrototype__proto.subtract = add_subtract__subtract; momentPrototype__proto.toArray = toArray; + momentPrototype__proto.toObject = toObject; momentPrototype__proto.toDate = toDate; momentPrototype__proto.toISOString = moment_format__toISOString; momentPrototype__proto.toJSON = moment_format__toISOString; @@ -4130,19 +4174,23 @@ return /******/ (function(modules) { // webpackBootstrap LT : 'h:mm A', L : 'MM/DD/YYYY', LL : 'MMMM D, YYYY', - LLL : 'MMMM D, YYYY LT', - LLLL : 'dddd, MMMM D, YYYY LT' + LLL : 'MMMM D, YYYY h:mm A', + LLLL : 'dddd, MMMM D, YYYY h:mm A' }; function longDateFormat (key) { - var output = this._longDateFormat[key]; - if (!output && this._longDateFormat[key.toUpperCase()]) { - output = this._longDateFormat[key.toUpperCase()].replace(/MMMM|MM|DD|dddd/g, function (val) { - return val.slice(1); - }); - this._longDateFormat[key] = output; + var format = this._longDateFormat[key], + formatUpper = this._longDateFormat[key.toUpperCase()]; + + if (format || !formatUpper) { + return format; } - return output; + + this._longDateFormat[key] = formatUpper.replace(/MMMM|MM|DD|dddd/g, function (val) { + return val.slice(1); + }); + + return this._longDateFormat[key]; } var defaultInvalidDate = 'Invalid date'; @@ -4351,12 +4399,29 @@ return /******/ (function(modules) { // webpackBootstrap return duration_add_subtract__addSubtract(this, input, value, -1); } + function absCeil (number) { + if (number < 0) { + return Math.floor(number); + } else { + return Math.ceil(number); + } + } + function bubble () { var milliseconds = this._milliseconds; var days = this._days; var months = this._months; var data = this._data; - var seconds, minutes, hours, years = 0; + var seconds, minutes, hours, years, monthsFromDays; + + // if we have a mix of positive and negative values, bubble down first + // check: https://github.com/moment/moment/issues/2166 + if (!((milliseconds >= 0 && days >= 0 && months >= 0) || + (milliseconds <= 0 && days <= 0 && months <= 0))) { + milliseconds += absCeil(monthsToDays(months) + days) * 864e5; + days = 0; + months = 0; + } // The following code bubbles up values, see the tests for // examples of what that means. @@ -4373,17 +4438,13 @@ return /******/ (function(modules) { // webpackBootstrap days += absFloor(hours / 24); - // Accurately convert days to years, assume start from year 0. - years = absFloor(daysToYears(days)); - days -= absFloor(yearsToDays(years)); - - // 30 days to a month - // TODO (iskren): Use anchor date (like 1st Jan) to compute this. - months += absFloor(days / 30); - days %= 30; + // convert days to months + monthsFromDays = absFloor(daysToMonths(days)); + months += monthsFromDays; + days -= absCeil(monthsToDays(monthsFromDays)); // 12 months -> 1 year - years += absFloor(months / 12); + years = absFloor(months / 12); months %= 12; data.days = days; @@ -4393,15 +4454,15 @@ return /******/ (function(modules) { // webpackBootstrap return this; } - function daysToYears (days) { + function daysToMonths (days) { // 400 years have 146097 days (taking into account leap year rules) - return days * 400 / 146097; + // 400 years have 12 months === 4800 + return days * 4800 / 146097; } - function yearsToDays (years) { - // years * 365 + absFloor(years / 4) - - // absFloor(years / 100) + absFloor(years / 400); - return years * 146097 / 400; + function monthsToDays (months) { + // the reverse of daysToMonths + return months * 146097 / 4800; } function as (units) { @@ -4413,11 +4474,11 @@ return /******/ (function(modules) { // webpackBootstrap if (units === 'month' || units === 'year') { days = this._days + milliseconds / 864e5; - months = this._months + daysToYears(days) * 12; + months = this._months + daysToMonths(days); return units === 'month' ? months : months / 12; } else { // handle milliseconds separately because of floating point math errors (issue #1867) - days = this._days + Math.round(yearsToDays(this._months / 12)); + days = this._days + Math.round(monthsToDays(this._months)); switch (units) { case 'week' : return days / 7 + milliseconds / 6048e5; case 'day' : return days + milliseconds / 864e5; @@ -4467,7 +4528,7 @@ return /******/ (function(modules) { // webpackBootstrap }; } - var duration_get__milliseconds = makeGetter('milliseconds'); + var milliseconds = makeGetter('milliseconds'); var seconds = makeGetter('seconds'); var minutes = makeGetter('minutes'); var hours = makeGetter('hours'); @@ -4545,13 +4606,36 @@ return /******/ (function(modules) { // webpackBootstrap var iso_string__abs = Math.abs; function iso_string__toISOString() { + // for ISO strings we do not use the normal bubbling rules: + // * milliseconds bubble up until they become hours + // * days do not bubble at all + // * months bubble up until they become years + // This is because there is no context-free conversion between hours and days + // (think of clock changes) + // and also not between days and months (28-31 days per month) + var seconds = iso_string__abs(this._milliseconds) / 1000; + var days = iso_string__abs(this._days); + var months = iso_string__abs(this._months); + var minutes, hours, years; + + // 3600 seconds -> 60 minutes -> 1 hour + minutes = absFloor(seconds / 60); + hours = absFloor(minutes / 60); + seconds %= 60; + minutes %= 60; + + // 12 months -> 1 year + years = absFloor(months / 12); + months %= 12; + + // inspired by https://github.com/dordille/moment-isoduration/blob/master/moment.isoduration.js - var Y = iso_string__abs(this.years()); - var M = iso_string__abs(this.months()); - var D = iso_string__abs(this.days()); - var h = iso_string__abs(this.hours()); - var m = iso_string__abs(this.minutes()); - var s = iso_string__abs(this.seconds() + this.milliseconds() / 1000); + var Y = years; + var M = months; + var D = days; + var h = hours; + var m = minutes; + var s = seconds; var total = this.asSeconds(); if (!total) { @@ -4588,7 +4672,7 @@ return /******/ (function(modules) { // webpackBootstrap duration_prototype__proto.valueOf = duration_as__valueOf; duration_prototype__proto._bubble = bubble; duration_prototype__proto.get = duration_get__get; - duration_prototype__proto.milliseconds = duration_get__milliseconds; + duration_prototype__proto.milliseconds = milliseconds; duration_prototype__proto.seconds = seconds; duration_prototype__proto.minutes = minutes; duration_prototype__proto.hours = hours; @@ -4626,7 +4710,7 @@ return /******/ (function(modules) { // webpackBootstrap // Side effect imports - utils_hooks__hooks.version = '2.10.3'; + utils_hooks__hooks.version = '2.10.6'; setHookCallback(local__createLocal); @@ -5041,21 +5125,21 @@ return /******/ (function(modules) { // webpackBootstrap var point; if (groupTemplate.style == 'circle') { point = exports.getSVGElement('circle', JSONcontainer, svgContainer); - point.setAttributeNS(null, "cx", x); - point.setAttributeNS(null, "cy", y); - point.setAttributeNS(null, "r", 0.5 * groupTemplate.size); + point.setAttributeNS(null, 'cx', x); + point.setAttributeNS(null, 'cy', y); + point.setAttributeNS(null, 'r', 0.5 * groupTemplate.size); } else { point = exports.getSVGElement('rect', JSONcontainer, svgContainer); - point.setAttributeNS(null, "x", x - 0.5 * groupTemplate.size); - point.setAttributeNS(null, "y", y - 0.5 * groupTemplate.size); - point.setAttributeNS(null, "width", groupTemplate.size); - point.setAttributeNS(null, "height", groupTemplate.size); + point.setAttributeNS(null, 'x', x - 0.5 * groupTemplate.size); + point.setAttributeNS(null, 'y', y - 0.5 * groupTemplate.size); + point.setAttributeNS(null, 'width', groupTemplate.size); + point.setAttributeNS(null, 'height', groupTemplate.size); } if (groupTemplate.style !== undefined) { - point.setAttributeNS(null, "style", groupTemplate.style); + point.setAttributeNS(null, 'style', groupTemplate.style); } - point.setAttributeNS(null, "class", groupTemplate.className + " vis-point"); + point.setAttributeNS(null, 'class', groupTemplate.className + ' vis-point'); //handle label if (labelObj) { @@ -5072,10 +5156,10 @@ return /******/ (function(modules) { // webpackBootstrap } if (labelObj.className) { - label.setAttributeNS(null, "class", labelObj.className + " vis-label"); + label.setAttributeNS(null, 'class', labelObj.className + ' vis-label'); } - label.setAttributeNS(null, "x", x); - label.setAttributeNS(null, "y", y); + label.setAttributeNS(null, 'x', x); + label.setAttributeNS(null, 'y', y); } return point; @@ -5095,13 +5179,13 @@ return /******/ (function(modules) { // webpackBootstrap y -= height; } var rect = exports.getSVGElement('rect', JSONcontainer, svgContainer); - rect.setAttributeNS(null, "x", x - 0.5 * width); - rect.setAttributeNS(null, "y", y); - rect.setAttributeNS(null, "width", width); - rect.setAttributeNS(null, "height", height); - rect.setAttributeNS(null, "class", className); + rect.setAttributeNS(null, 'x', x - 0.5 * width); + rect.setAttributeNS(null, 'y', y); + rect.setAttributeNS(null, 'width', width); + rect.setAttributeNS(null, 'height', height); + rect.setAttributeNS(null, 'class', className); if (style) { - rect.setAttributeNS(null, "style", style); + rect.setAttributeNS(null, 'style', style); } } }; @@ -5731,8 +5815,8 @@ return /******/ (function(modules) { // webpackBootstrap // TODO: extend order by an Object {field:String, direction:String} // where direction can be 'asc' or 'desc' else { - throw new TypeError('Order must be a function or a string'); - } + throw new TypeError('Order must be a function or a string'); + } }; /** @@ -6508,9 +6592,7 @@ return /******/ (function(modules) { // webpackBootstrap if (this._ids[id]) { delete this._ids[id]; removed.push(id); - } else { - // nothing interesting for me :-( - } + } else {} } } @@ -6554,18 +6636,20 @@ return /******/ (function(modules) { // webpackBootstrap module.exports = DataView; + // nothing interesting for me :-( + /***/ }, /* 11 */ /***/ function(module, exports, __webpack_require__) { 'use strict'; - var Emitter = __webpack_require__(13); + var Emitter = __webpack_require__(12); var DataSet = __webpack_require__(8); var DataView = __webpack_require__(10); var util = __webpack_require__(1); - var Point3d = __webpack_require__(14); - var Point2d = __webpack_require__(12); + var Point3d = __webpack_require__(13); + var Point2d = __webpack_require__(14); var Camera = __webpack_require__(15); var Filter = __webpack_require__(16); var Slider = __webpack_require__(17); @@ -6797,11 +6881,9 @@ return /******/ (function(modules) { // webpackBootstrap if (backgroundColor.fill !== undefined) fill = backgroundColor.fill; if (backgroundColor.stroke !== undefined) stroke = backgroundColor.stroke; if (backgroundColor.strokeWidth !== undefined) strokeWidth = backgroundColor.strokeWidth; - } else if (backgroundColor === undefined) { - // use use defaults - } else { - throw 'Unsupported type of backgroundColor'; - } + } else if (backgroundColor === undefined) {} else { + throw 'Unsupported type of backgroundColor'; + } this.frame.style.backgroundColor = fill; this.frame.style.borderColor = stroke; @@ -7507,9 +7589,9 @@ return /******/ (function(modules) { // webpackBootstrap widthMin = dotSize / 2; // px widthMax = dotSize / 2 + dotSize * 2; // Todo: put this in one function } else { - widthMin = 20; // px - widthMax = 20; // px - } + widthMin = 20; // px + widthMax = 20; // px + } var height = Math.max(this.frame.clientHeight * 0.25, 100); var top = this.margin; @@ -8045,9 +8127,9 @@ return /******/ (function(modules) { // webpackBootstrap strokeStyle = this.axisColor; // TODO: should be customizable } } else { - fillStyle = 'gray'; - strokeStyle = this.axisColor; - } + fillStyle = 'gray'; + strokeStyle = this.axisColor; + } ctx.lineWidth = this._getStrokeWidth(point); ctx.fillStyle = fillStyle; @@ -8802,26 +8884,10 @@ return /******/ (function(modules) { // webpackBootstrap module.exports = Graph3d; -/***/ }, -/* 12 */ -/***/ function(module, exports) { - - /** - * @prototype Point2d - * @param {Number} [x] - * @param {Number} [y] - */ - "use strict"; - - function Point2d(x, y) { - this.x = x !== undefined ? x : 0; - this.y = y !== undefined ? y : 0; - } - - module.exports = Point2d; + // use use defaults /***/ }, -/* 13 */ +/* 12 */ /***/ function(module, exports) { @@ -8991,7 +9057,7 @@ return /******/ (function(modules) { // webpackBootstrap /***/ }, -/* 14 */ +/* 13 */ /***/ function(module, exports) { /** @@ -9073,13 +9139,31 @@ return /******/ (function(modules) { // webpackBootstrap module.exports = Point3d; +/***/ }, +/* 14 */ +/***/ function(module, exports) { + + /** + * @prototype Point2d + * @param {Number} [x] + * @param {Number} [y] + */ + "use strict"; + + function Point2d(x, y) { + this.x = x !== undefined ? x : 0; + this.y = y !== undefined ? y : 0; + } + + module.exports = Point2d; + /***/ }, /* 15 */ /***/ function(module, exports, __webpack_require__) { 'use strict'; - var Point3d = __webpack_require__(14); + var Point3d = __webpack_require__(13); /** * @class Camera @@ -9923,7 +10007,7 @@ return /******/ (function(modules) { // webpackBootstrap 'use strict'; - var Emitter = __webpack_require__(13); + var Emitter = __webpack_require__(12); var Hammer = __webpack_require__(20); var moment = __webpack_require__(2); var util = __webpack_require__(1); @@ -10320,10 +10404,7 @@ return /******/ (function(modules) { // webpackBootstrap var getEnd = function getEnd(item) { var end = item.data.end != undefined ? item.data.end : item.data.start; return util.convert(end, 'Date').valueOf(); - } - - // calculate the date of the left side and right side of the items given - ; + }; interval = max - min; // ms @@ -10331,6 +10412,8 @@ return /******/ (function(modules) { // webpackBootstrap interval = 10; } factor = interval / _this.props.center.width; + + // calculate the date of the left side and right side of the items given util.forEach(_this.itemSet.items, (function (item) { item.show(); @@ -13991,9 +14074,7 @@ return /******/ (function(modules) { // webpackBootstrap /** * Destroy the component. Cleanup DOM and event listeners */ - Component.prototype.destroy = function () { - // should be implemented by the component - }; + Component.prototype.destroy = function () {}; /** * Test whether the component is resized since the last time _isResized() was @@ -14012,6 +14093,8 @@ return /******/ (function(modules) { // webpackBootstrap module.exports = Component; + // should be implemented by the component + /***/ }, /* 27 */ /***/ function(module, exports) { @@ -14086,16 +14169,16 @@ return /******/ (function(modules) { // webpackBootstrap } startDate.dayOfYear(start.dayOfYear()); startDate.year(start.year()); - startDate.subtract(7, 'days'); + startDate.subtract(7, "days"); endDate.dayOfYear(start.dayOfYear()); endDate.year(start.year()); - endDate.subtract(7 - offset, 'days'); + endDate.subtract(7 - offset, "days"); - runUntil.add(1, 'weeks'); + runUntil.add(1, "weeks"); break; case "weekly": - var dayOffset = endDate.diff(startDate, 'days'); + var dayOffset = endDate.diff(startDate, "days"); var day = startDate.day(); // set the start date to the range.start @@ -14107,12 +14190,12 @@ return /******/ (function(modules) { // webpackBootstrap // force startDate.day(day); endDate.day(day); - endDate.add(dayOffset, 'days'); + endDate.add(dayOffset, "days"); - startDate.subtract(1, 'weeks'); - endDate.subtract(1, 'weeks'); + startDate.subtract(1, "weeks"); + endDate.subtract(1, "weeks"); - runUntil.add(1, 'weeks'); + runUntil.add(1, "weeks"); break; case "monthly": if (startDate.month() != endDate.month()) { @@ -14120,26 +14203,26 @@ return /******/ (function(modules) { // webpackBootstrap } startDate.month(start.month()); startDate.year(start.year()); - startDate.subtract(1, 'months'); + startDate.subtract(1, "months"); endDate.month(start.month()); endDate.year(start.year()); - endDate.subtract(1, 'months'); - endDate.add(offset, 'months'); + endDate.subtract(1, "months"); + endDate.add(offset, "months"); - runUntil.add(1, 'months'); + runUntil.add(1, "months"); break; case "yearly": if (startDate.year() != endDate.year()) { offset = 1; } startDate.year(start.year()); - startDate.subtract(1, 'years'); + startDate.subtract(1, "years"); endDate.year(start.year()); - endDate.subtract(1, 'years'); - endDate.add(offset, 'years'); + endDate.subtract(1, "years"); + endDate.add(offset, "years"); - runUntil.add(1, 'years'); + runUntil.add(1, "years"); break; default: console.log("Wrong repeat format, allowed are: daily, weekly, monthly, yearly. Given:", hiddenDates[i].repeat); @@ -14149,20 +14232,20 @@ return /******/ (function(modules) { // webpackBootstrap body.hiddenDates.push({ start: startDate.valueOf(), end: endDate.valueOf() }); switch (hiddenDates[i].repeat) { case "daily": - startDate.add(1, 'days'); - endDate.add(1, 'days'); + startDate.add(1, "days"); + endDate.add(1, "days"); break; case "weekly": - startDate.add(1, 'weeks'); - endDate.add(1, 'weeks'); + startDate.add(1, "weeks"); + endDate.add(1, "weeks"); break; case "monthly": - startDate.add(1, 'months'); - endDate.add(1, 'months'); + startDate.add(1, "months"); + endDate.add(1, "months"); break; case "yearly": - startDate.add(1, 'y'); - endDate.add(1, 'y'); + startDate.add(1, "y"); + endDate.add(1, "y"); break; default: console.log("Wrong repeat format, allowed are: daily, weekly, monthly, yearly. Given:", hiddenDates[i].repeat); @@ -14209,14 +14292,14 @@ return /******/ (function(modules) { // webpackBootstrap } // j start inside i else if (hiddenDates[j].start >= hiddenDates[i].start && hiddenDates[j].start <= hiddenDates[i].end) { - hiddenDates[i].end = hiddenDates[j].end; - hiddenDates[j].remove = true; - } - // j end inside i - else if (hiddenDates[j].end >= hiddenDates[i].start && hiddenDates[j].end <= hiddenDates[i].end) { - hiddenDates[i].start = hiddenDates[j].start; - hiddenDates[j].remove = true; - } + hiddenDates[i].end = hiddenDates[j].end; + hiddenDates[j].remove = true; + } + // j end inside i + else if (hiddenDates[j].end >= hiddenDates[i].start && hiddenDates[j].end <= hiddenDates[i].end) { + hiddenDates[i].start = hiddenDates[j].start; + hiddenDates[j].remove = true; + } } } } @@ -14482,7 +14565,7 @@ return /******/ (function(modules) { // webpackBootstrap 'use strict'; - var Emitter = __webpack_require__(13); + var Emitter = __webpack_require__(12); var Hammer = __webpack_require__(20); var hammerUtil = __webpack_require__(25); var util = __webpack_require__(1); @@ -15414,7 +15497,7 @@ return /******/ (function(modules) { // webpackBootstrap if (newScrollTop != oldScrollTop) { this._redraw(); // TODO: this causes two redraws when dragging, the other is triggered by rangechange already - this.emit("verticalDrag"); + this.emit('verticalDrag'); } }; @@ -15484,13 +15567,13 @@ return /******/ (function(modules) { // webpackBootstrap var util = __webpack_require__(1); var DataSet = __webpack_require__(8); var DataView = __webpack_require__(10); - var TimeStep = __webpack_require__(34); + var TimeStep = __webpack_require__(30); var Component = __webpack_require__(26); - var Group = __webpack_require__(30); + var Group = __webpack_require__(31); var BackgroundGroup = __webpack_require__(35); var BoxItem = __webpack_require__(36); var PointItem = __webpack_require__(37); - var RangeItem = __webpack_require__(32); + var RangeItem = __webpack_require__(33); var BackgroundItem = __webpack_require__(38); var UNGROUPED = '__ungrouped__'; // reserved group id for ungrouped items @@ -16832,11 +16915,11 @@ return /******/ (function(modules) { // webpackBootstrap // confirm moving the item itemData = this._cloneItemData(itemData); // convert start and end to the correct type - me.options.onMoving(itemData, function (itemData) { + me.options.onMoving(itemData, (function (itemData) { if (itemData) { - props.item.setData(itemData); + props.item.setData(this._cloneItemData(itemData, 'Date')); } - }); + }).bind(this)); }).bind(this)); this.stackDirty = true; // force re-stacking of all items next redraw @@ -17000,25 +17083,25 @@ return /******/ (function(modules) { // webpackBootstrap } // if dragged group was move downwards everything above should have an offset else if (origOrder[curPos + orgOffset] == draggedId) { - orgOffset = 1; - continue; - } - // found a group (apart from dragged group) that has the wrong position -> switch with the - // group at the position where other one should be, fix index arrays and continue - else { - var slippedPosition = newOrder.indexOf(origOrder[curPos + orgOffset]); - var switchGroup = groupsData.get(newOrder[curPos + newOffset]); - var shouldBeGroup = groupsData.get(origOrder[curPos + orgOffset]); - this.options.groupOrderSwap(switchGroup, shouldBeGroup, groupsData); - groupsData.update(switchGroup); - groupsData.update(shouldBeGroup); - - var switchGroupId = newOrder[curPos + newOffset]; - newOrder[curPos + newOffset] = origOrder[curPos + orgOffset]; - newOrder[slippedPosition] = switchGroupId; - - curPos++; - } + orgOffset = 1; + continue; + } + // found a group (apart from dragged group) that has the wrong position -> switch with the + // group at the position where other one should be, fix index arrays and continue + else { + var slippedPosition = newOrder.indexOf(origOrder[curPos + orgOffset]); + var switchGroup = groupsData.get(newOrder[curPos + newOffset]); + var shouldBeGroup = groupsData.get(origOrder[curPos + orgOffset]); + this.options.groupOrderSwap(switchGroup, shouldBeGroup, groupsData); + groupsData.update(switchGroup); + groupsData.update(shouldBeGroup); + + var switchGroupId = newOrder[curPos + newOffset]; + newOrder[curPos + newOffset] = origOrder[curPos + orgOffset]; + newOrder[slippedPosition] = switchGroupId; + + curPos++; + } } } } @@ -17343,14 +17426,18 @@ return /******/ (function(modules) { // webpackBootstrap * to the type (Date, Moment, ...) configured in the DataSet. If not configured, * start and end are converted to Date. * @param {Object} itemData, typically `item.data` + * @param {string} [type] Optional Date type. If not provided, the type from the DataSet is taken * @return {Object} The cloned object * @private */ - ItemSet.prototype._cloneItemData = function (itemData) { + ItemSet.prototype._cloneItemData = function (itemData, type) { var clone = util.extend({}, itemData); - // convert start and end date to the type (Date, Moment, ...) configured in the DataSet - var type = this.itemsData.getDataSet()._options.type; + if (!type) { + // convert start and end date to the type (Date, Moment, ...) configured in the DataSet + type = this.itemsData.getDataSet()._options.type; + } + if (clone.start != undefined) { clone.start = util.convert(clone.start, type && type.start || 'Date'); } @@ -17369,2038 +17456,2038 @@ return /******/ (function(modules) { // webpackBootstrap 'use strict'; + var moment = __webpack_require__(2); + var DateUtil = __webpack_require__(27); var util = __webpack_require__(1); - var stack = __webpack_require__(31); - var RangeItem = __webpack_require__(32); /** - * @constructor Group - * @param {Number | String} groupId - * @param {Object} data - * @param {ItemSet} itemSet + * @constructor TimeStep + * The class TimeStep is an iterator for dates. You provide a start date and an + * end date. The class itself determines the best scale (step size) based on the + * provided start Date, end Date, and minimumStep. + * + * If minimumStep is provided, the step size is chosen as close as possible + * to the minimumStep but larger than minimumStep. If minimumStep is not + * provided, the scale is set to 1 DAY. + * The minimumStep should correspond with the onscreen size of about 6 characters + * + * Alternatively, you can set a scale by hand. + * After creation, you can initialize the class by executing first(). Then you + * can iterate from the start date to the end date via next(). You can check if + * the end date is reached with the function hasNext(). After each step, you can + * retrieve the current date via getCurrent(). + * The TimeStep has scales ranging from milliseconds, seconds, minutes, hours, + * days, to years. + * + * Version: 1.2 + * + * @param {Date} [start] The start date, for example new Date(2010, 9, 21) + * or new Date(2010, 9, 21, 23, 45, 00) + * @param {Date} [end] The end date + * @param {Number} [minimumStep] Optional. Minimum step size in milliseconds */ - function Group(groupId, data, itemSet) { - this.groupId = groupId; - this.subgroups = {}; - this.subgroupIndex = 0; - this.subgroupOrderer = data && data.subgroupOrder; - this.itemSet = itemSet; - - this.dom = {}; - this.props = { - label: { - width: 0, - height: 0 - } - }; - this.className = null; + function TimeStep(start, end, minimumStep, hiddenDates) { + this.moment = moment; - this.items = {}; // items filtered by groupId of this group - this.visibleItems = []; // items currently visible in window - this.orderedItems = { - byStart: [], - byEnd: [] - }; - this.checkRangedItems = false; // needed to refresh the ranged items if the window is programatically changed with NO overlap. - var me = this; - this.itemSet.body.emitter.on("checkRangedItems", function () { - me.checkRangedItems = true; - }); + // variables + this.current = this.moment(); + this._start = this.moment(); + this._end = this.moment(); - this._create(); + this.autoScale = true; + this.scale = 'day'; + this.step = 1; - this.setData(data); - } + // initialize the range + this.setRange(start, end, minimumStep); - /** - * Create DOM elements for the group - * @private - */ - Group.prototype._create = function () { - var label = document.createElement('div'); - if (this.itemSet.options.groupEditable.order) { - label.className = 'vis-label draggable'; - } else { - label.className = 'vis-label'; + // hidden Dates options + this.switchedDay = false; + this.switchedMonth = false; + this.switchedYear = false; + this.hiddenDates = hiddenDates; + if (hiddenDates === undefined) { + this.hiddenDates = []; } - this.dom.label = label; - var inner = document.createElement('div'); - inner.className = 'vis-inner'; - label.appendChild(inner); - this.dom.inner = inner; + this.format = TimeStep.FORMAT; // default formatting + } - var foreground = document.createElement('div'); - foreground.className = 'vis-group'; - foreground['timeline-group'] = this; - this.dom.foreground = foreground; + // Time formatting + TimeStep.FORMAT = { + minorLabels: { + millisecond: 'SSS', + second: 's', + minute: 'HH:mm', + hour: 'HH:mm', + weekday: 'ddd D', + day: 'D', + month: 'MMM', + year: 'YYYY' + }, + majorLabels: { + millisecond: 'HH:mm:ss', + second: 'D MMMM HH:mm', + minute: 'ddd D MMMM', + hour: 'ddd D MMMM', + weekday: 'MMMM YYYY', + day: 'MMMM YYYY', + month: 'YYYY', + year: '' + } + }; - this.dom.background = document.createElement('div'); - this.dom.background.className = 'vis-group'; + /** + * Set custom constructor function for moment. Can be used to set dates + * to UTC or to set a utcOffset. + * @param {function} moment + */ + TimeStep.prototype.setMoment = function (moment) { + this.moment = moment; - this.dom.axis = document.createElement('div'); - this.dom.axis.className = 'vis-group'; + // update the date properties, can have a new utcOffset + this.current = this.moment(this.current); + this._start = this.moment(this._start); + this._end = this.moment(this._end); + }; - // create a hidden marker to detect when the Timelines container is attached - // to the DOM, or the style of a parent of the Timeline is changed from - // display:none is changed to visible. - this.dom.marker = document.createElement('div'); - this.dom.marker.style.visibility = 'hidden'; - this.dom.marker.innerHTML = '?'; - this.dom.background.appendChild(this.dom.marker); + /** + * Set custom formatting for the minor an major labels of the TimeStep. + * Both `minorLabels` and `majorLabels` are an Object with properties: + * 'millisecond', 'second', 'minute', 'hour', 'weekday', 'day', 'month', 'year'. + * @param {{minorLabels: Object, majorLabels: Object}} format + */ + TimeStep.prototype.setFormat = function (format) { + var defaultFormat = util.deepExtend({}, TimeStep.FORMAT); + this.format = util.deepExtend(defaultFormat, format); }; /** - * Set the group data for this group - * @param {Object} data Group data, can contain properties content and className + * Set a new range + * If minimumStep is provided, the step size is chosen as close as possible + * to the minimumStep but larger than minimumStep. If minimumStep is not + * provided, the scale is set to 1 DAY. + * The minimumStep should correspond with the onscreen size of about 6 characters + * @param {Date} [start] The start date and time. + * @param {Date} [end] The end date and time. + * @param {int} [minimumStep] Optional. Minimum step size in milliseconds */ - Group.prototype.setData = function (data) { - // update contents - var content; - if (this.itemSet.options && this.itemSet.options.groupTemplate) { - content = this.itemSet.options.groupTemplate(data); - } else { - content = data && data.content; + TimeStep.prototype.setRange = function (start, end, minimumStep) { + if (!(start instanceof Date) || !(end instanceof Date)) { + throw 'No legal start or end date in method setRange'; } - if (content instanceof Element) { - this.dom.inner.appendChild(content); - while (this.dom.inner.firstChild) { - this.dom.inner.removeChild(this.dom.inner.firstChild); - } - this.dom.inner.appendChild(content); - } else if (content !== undefined && content !== null) { - this.dom.inner.innerHTML = content; - } else { - this.dom.inner.innerHTML = this.groupId || ''; // groupId can be null + this._start = start != undefined ? this.moment(start.valueOf()) : new Date(); + this._end = end != undefined ? this.moment(end.valueOf()) : new Date(); + + if (this.autoScale) { + this.setMinimumStep(minimumStep); } + }; - // update title - this.dom.label.title = data && data.title || ''; + /** + * Set the range iterator to the start date. + */ + TimeStep.prototype.start = function () { + this.current = this._start.clone(); + this.roundToMinor(); + }; - if (!this.dom.inner.firstChild) { - util.addClassName(this.dom.inner, 'vis-hidden'); - } else { - util.removeClassName(this.dom.inner, 'vis-hidden'); + /** + * Round the current date to the first minor date value + * This must be executed once when the current date is set to start Date + */ + TimeStep.prototype.roundToMinor = function () { + // round to floor + // IMPORTANT: we have no breaks in this switch! (this is no bug) + // noinspection FallThroughInSwitchStatementJS + switch (this.scale) { + case 'year': + this.current.year(this.step * Math.floor(this.current.year() / this.step)); + this.current.month(0); + case 'month': + this.current.date(1); + case 'day': // intentional fall through + case 'weekday': + this.current.hours(0); + case 'hour': + this.current.minutes(0); + case 'minute': + this.current.seconds(0); + case 'second': + this.current.milliseconds(0); + //case 'millisecond': // nothing to do for milliseconds } - // update className - var className = data && data.className || null; - if (className != this.className) { - if (this.className) { - util.removeClassName(this.dom.label, this.className); - util.removeClassName(this.dom.foreground, this.className); - util.removeClassName(this.dom.background, this.className); - util.removeClassName(this.dom.axis, this.className); + if (this.step != 1) { + // round down to the first minor value that is a