From 57374b33aaf1f252f0e709561c0a15b40427aed6 Mon Sep 17 00:00:00 2001 From: jos Date: Thu, 21 Aug 2014 17:23:36 +0200 Subject: [PATCH] Implemented localization for Network --- HISTORY.md | 1 + dist/vis.js | 1777 +++++++++++++---------- dist/vis.min.css | 2 +- docs/network.html | 1773 +++++++++++----------- docs/timeline.html | 10 +- examples/network/31_localization.html | 231 +++ examples/network/index.html | 1 + lib/network/Network.js | 26 +- lib/network/locales.js | 4 +- lib/network/mixins/ManipulationMixin.js | 52 +- 10 files changed, 2217 insertions(+), 1660 deletions(-) create mode 100644 examples/network/31_localization.html diff --git a/HISTORY.md b/HISTORY.md index 57311976..41eed1c1 100644 --- a/HISTORY.md +++ b/HISTORY.md @@ -15,6 +15,7 @@ http://visjs.org - A fix in reading group properties for a node. - Fixed physics solving stopping when a support node was not moving. +- Added localization support. ### Graph2D diff --git a/dist/vis.js b/dist/vis.js index 01527a24..f4a61c61 100644 --- a/dist/vis.js +++ b/dist/vis.js @@ -100,44 +100,44 @@ return /******/ (function(modules) { // webpackBootstrap // Timeline exports.Timeline = __webpack_require__(17); - exports.Graph2d = __webpack_require__(35); + exports.Graph2d = __webpack_require__(36); exports.timeline = { - DataStep: __webpack_require__(40), + DataStep: __webpack_require__(39), Range: __webpack_require__(20), - stack: __webpack_require__(30), + stack: __webpack_require__(31), TimeStep: __webpack_require__(25), components: { items: { - Item: __webpack_require__(32), - ItemBox: __webpack_require__(33), - ItemPoint: __webpack_require__(34), - ItemRange: __webpack_require__(31) + Item: __webpack_require__(33), + ItemBox: __webpack_require__(34), + ItemPoint: __webpack_require__(35), + ItemRange: __webpack_require__(32) }, Component: __webpack_require__(22), CurrentTime: __webpack_require__(26), - CustomTime: __webpack_require__(27), - DataAxis: __webpack_require__(37), - GraphGroup: __webpack_require__(38), - Group: __webpack_require__(29), - ItemSet: __webpack_require__(28), - Legend: __webpack_require__(39), - LineGraph: __webpack_require__(36), + CustomTime: __webpack_require__(28), + DataAxis: __webpack_require__(38), + GraphGroup: __webpack_require__(40), + Group: __webpack_require__(30), + ItemSet: __webpack_require__(29), + Legend: __webpack_require__(41), + LineGraph: __webpack_require__(37), TimeAxis: __webpack_require__(24) } }; // Network - exports.Network = __webpack_require__(41); + exports.Network = __webpack_require__(42); exports.network = { - Edge: __webpack_require__(48), - Groups: __webpack_require__(45), - Images: __webpack_require__(46), - Node: __webpack_require__(47), - Popup: __webpack_require__(49), - dotparser: __webpack_require__(43), - gephiParser: __webpack_require__(44) + Edge: __webpack_require__(49), + Groups: __webpack_require__(46), + Images: __webpack_require__(47), + Node: __webpack_require__(48), + Popup: __webpack_require__(50), + dotparser: __webpack_require__(44), + gephiParser: __webpack_require__(45) }; // Deprecated since v3.0.0 @@ -1415,19 +1415,18 @@ return /******/ (function(modules) { // webpackBootstrap /***/ function(module, exports, __webpack_require__) { var __WEBPACK_AMD_DEFINE_RESULT__;/* WEBPACK VAR INJECTION */(function(global, module) {//! moment.js - //! version : 2.7.0 + //! version : 2.8.1 //! authors : Tim Wood, Iskren Chernev, Moment.js contributors //! license : MIT //! momentjs.com (function (undefined) { - /************************************ Constants ************************************/ var moment, - VERSION = "2.7.0", + VERSION = '2.8.1', // the global-scope this is NOT the global object in Node.js globalScope = typeof global !== 'undefined' ? global : this, oldGlobalMoment, @@ -1442,22 +1441,11 @@ return /******/ (function(modules) { // webpackBootstrap SECOND = 5, MILLISECOND = 6, - // internal storage for language config files - languages = {}, - - // moment internal properties - momentProperties = { - _isAMomentObject: null, - _i : null, - _f : null, - _l : null, - _strict : null, - _tzm : null, - _isUTC : null, - _offset : null, // optional. Combine with _isUTC - _pf : null, - _lang : null // optional - }, + // internal storage for locale config files + locales = {}, + + // extra moment internal properties (plugins register props here) + momentProperties = [], // check for nodeJS hasModule = (typeof module !== 'undefined' && module.exports), @@ -1563,12 +1551,11 @@ return /******/ (function(modules) { // webpackBootstrap // default relative time thresholds relativeTimeThresholds = { - s: 45, //seconds to minutes - m: 45, //minutes to hours - h: 22, //hours to days - dd: 25, //days to month (month == 1) - dm: 45, //days to months (months > 1) - dy: 345 //days to year + s: 45, // seconds to minute + m: 45, // minutes to hour + h: 22, // hours to day + d: 26, // days to month + M: 11 // months to year }, // tokens to ordinalize and pad @@ -1580,10 +1567,10 @@ return /******/ (function(modules) { // webpackBootstrap return this.month() + 1; }, MMM : function (format) { - return this.lang().monthsShort(this, format); + return this.localeData().monthsShort(this, format); }, MMMM : function (format) { - return this.lang().months(this, format); + return this.localeData().months(this, format); }, D : function () { return this.date(); @@ -1595,13 +1582,13 @@ return /******/ (function(modules) { // webpackBootstrap return this.day(); }, dd : function (format) { - return this.lang().weekdaysMin(this, format); + return this.localeData().weekdaysMin(this, format); }, ddd : function (format) { - return this.lang().weekdaysShort(this, format); + return this.localeData().weekdaysShort(this, format); }, dddd : function (format) { - return this.lang().weekdays(this, format); + return this.localeData().weekdays(this, format); }, w : function () { return this.week(); @@ -1647,10 +1634,10 @@ return /******/ (function(modules) { // webpackBootstrap return this.isoWeekday(); }, a : function () { - return this.lang().meridiem(this.hours(), this.minutes(), true); + return this.localeData().meridiem(this.hours(), this.minutes(), true); }, A : function () { - return this.lang().meridiem(this.hours(), this.minutes(), false); + return this.localeData().meridiem(this.hours(), this.minutes(), false); }, H : function () { return this.hours(); @@ -1678,19 +1665,19 @@ return /******/ (function(modules) { // webpackBootstrap }, Z : function () { var a = -this.zone(), - b = "+"; + b = '+'; if (a < 0) { a = -a; - b = "-"; + b = '-'; } - return b + leftZeroFill(toInt(a / 60), 2) + ":" + leftZeroFill(toInt(a) % 60, 2); + return b + leftZeroFill(toInt(a / 60), 2) + ':' + leftZeroFill(toInt(a) % 60, 2); }, ZZ : function () { var a = -this.zone(), - b = "+"; + b = '+'; if (a < 0) { a = -a; - b = "-"; + b = '-'; } return b + leftZeroFill(toInt(a / 60), 2) + leftZeroFill(toInt(a) % 60, 2); }, @@ -1708,6 +1695,8 @@ return /******/ (function(modules) { // webpackBootstrap } }, + deprecations = {}, + lists = ['months', 'monthsShort', 'weekdays', 'weekdaysShort', 'weekdaysMin']; // Pick the first defined of two or three arguments. dfl comes from @@ -1716,7 +1705,7 @@ return /******/ (function(modules) { // webpackBootstrap switch (arguments.length) { case 2: return a != null ? a : b; case 3: return a != null ? a : b != null ? b : c; - default: throw new Error("Implement me"); + default: throw new Error('Implement me'); } } @@ -1737,23 +1726,31 @@ return /******/ (function(modules) { // webpackBootstrap }; } + function printMsg(msg) { + if (moment.suppressDeprecationWarnings === false && + typeof console !== 'undefined' && console.warn) { + console.warn("Deprecation warning: " + msg); + } + } + function deprecate(msg, fn) { var firstTime = true; - function printMsg() { - if (moment.suppressDeprecationWarnings === false && - typeof console !== 'undefined' && console.warn) { - console.warn("Deprecation warning: " + msg); - } - } return extend(function () { if (firstTime) { - printMsg(); + printMsg(msg); firstTime = false; } return fn.apply(this, arguments); }, fn); } + function deprecateSimple(name, msg) { + if (!deprecations[name]) { + printMsg(msg); + deprecations[name] = true; + } + } + function padToken(func, count) { return function (a) { return leftZeroFill(func.call(this, a), count); @@ -1761,7 +1758,7 @@ return /******/ (function(modules) { // webpackBootstrap } function ordinalizeToken(func, period) { return function (a) { - return this.lang().ordinal(func.call(this, a), period); + return this.localeData().ordinal(func.call(this, a), period); }; } @@ -1780,14 +1777,16 @@ return /******/ (function(modules) { // webpackBootstrap Constructors ************************************/ - function Language() { - + function Locale() { } // Moment prototype object - function Moment(config) { - checkOverflow(config); - extend(this, config); + function Moment(config, skipOverflow) { + if (skipOverflow !== false) { + checkOverflow(config); + } + copyConfig(this, config); + this._d = new Date(+config._d); } // Duration Constructor @@ -1821,6 +1820,8 @@ return /******/ (function(modules) { // webpackBootstrap this._data = {}; + this._locale = moment.localeData(); + this._bubble(); } @@ -1836,26 +1837,62 @@ return /******/ (function(modules) { // webpackBootstrap } } - if (b.hasOwnProperty("toString")) { + if (b.hasOwnProperty('toString')) { a.toString = b.toString; } - if (b.hasOwnProperty("valueOf")) { + if (b.hasOwnProperty('valueOf')) { a.valueOf = b.valueOf; } return a; } - function cloneMoment(m) { - var result = {}, i; - for (i in m) { - if (m.hasOwnProperty(i) && momentProperties.hasOwnProperty(i)) { - result[i] = m[i]; + function copyConfig(to, from) { + var i, prop, val; + + if (typeof from._isAMomentObject !== 'undefined') { + to._isAMomentObject = from._isAMomentObject; + } + if (typeof from._i !== 'undefined') { + to._i = from._i; + } + if (typeof from._f !== 'undefined') { + to._f = from._f; + } + if (typeof from._l !== 'undefined') { + to._l = from._l; + } + if (typeof from._strict !== 'undefined') { + to._strict = from._strict; + } + if (typeof from._tzm !== 'undefined') { + to._tzm = from._tzm; + } + if (typeof from._isUTC !== 'undefined') { + to._isUTC = from._isUTC; + } + if (typeof from._offset !== 'undefined') { + to._offset = from._offset; + } + if (typeof from._pf !== 'undefined') { + to._pf = from._pf; + } + if (typeof from._locale !== 'undefined') { + to._locale = from._locale; + } + + if (momentProperties.length > 0) { + for (i in momentProperties) { + prop = momentProperties[i]; + val = from[prop]; + if (typeof val !== 'undefined') { + to[prop] = val; + } } } - return result; + return to; } function absRound(number) { @@ -1878,7 +1915,51 @@ return /******/ (function(modules) { // webpackBootstrap return (sign ? (forceSign ? '+' : '') : '-') + output; } - // helper function for _.addTime and _.subtractTime + function positiveMomentsDifference(base, other) { + var res = {milliseconds: 0, months: 0}; + + res.months = other.month() - base.month() + + (other.year() - base.year()) * 12; + if (base.clone().add(res.months, 'M').isAfter(other)) { + --res.months; + } + + res.milliseconds = +other - +(base.clone().add(res.months, 'M')); + + return res; + } + + function momentsDifference(base, other) { + var res; + other = makeAs(other, base); + if (base.isBefore(other)) { + res = positiveMomentsDifference(base, other); + } else { + res = positiveMomentsDifference(other, base); + res.milliseconds = -res.milliseconds; + res.months = -res.months; + } + + return res; + } + + // TODO: remove 'name' arg after deprecation is removed + function createAdder(direction, name) { + return function (val, period) { + var dur, tmp; + //invert the arguments, but complain about it + if (period !== null && !isNaN(+period)) { + deprecateSimple(name, "moment()." + name + "(period, number) is deprecated. Please use moment()." + name + "(number, period)."); + tmp = val; val = period; period = tmp; + } + + val = typeof val === 'string' ? +val : val; + dur = moment.duration(val, period); + addOrSubtractDurationFromMoment(this, dur, direction); + return this; + }; + } + function addOrSubtractDurationFromMoment(mom, duration, isAdding, updateOffset) { var milliseconds = duration._milliseconds, days = duration._days, @@ -1905,8 +1986,8 @@ return /******/ (function(modules) { // webpackBootstrap } function isDate(input) { - return Object.prototype.toString.call(input) === '[object Date]' || - input instanceof Date; + return Object.prototype.toString.call(input) === '[object Date]' || + input instanceof Date; } // compare two arrays, return the number of differences @@ -1966,7 +2047,7 @@ return /******/ (function(modules) { // webpackBootstrap moment[field] = function (format, index) { var i, getter, - method = moment.fn._lang[field], + method = moment._locale[field], results = []; if (typeof format === 'number') { @@ -1976,7 +2057,7 @@ return /******/ (function(modules) { // webpackBootstrap getter = function (i) { var m = moment().utc().set(setter, i); - return method.call(moment.fn._lang, m, format || ''); + return method.call(moment._locale, m, format || ''); }; if (index != null) { @@ -2061,10 +2142,50 @@ return /******/ (function(modules) { // webpackBootstrap return m._isValid; } - function normalizeLanguage(key) { + function normalizeLocale(key) { return key ? key.toLowerCase().replace('_', '-') : key; } + // pick the locale from the array + // try ['en-au', 'en-gb'] as 'en-au', 'en-gb', 'en', as in move through the list trying each + // substring from most specific to least, but move to the next array item if it's a more specific variant than the current root + function chooseLocale(names) { + var i = 0, j, next, locale, split; + + while (i < names.length) { + split = normalizeLocale(names[i]).split('-'); + j = split.length; + next = normalizeLocale(names[i + 1]); + next = next ? next.split('-') : null; + while (j > 0) { + locale = loadLocale(split.slice(0, j).join('-')); + if (locale) { + return locale; + } + if (next && next.length >= j && compareArrays(split, next, true) >= j - 1) { + //the next array item is better than a shallower substring of this one + break; + } + j--; + } + i++; + } + return null; + } + + function loadLocale(name) { + var oldLocale = null; + if (!locales[name] && hasModule) { + try { + oldLocale = moment.locale(); + !(function webpackMissingModule() { var e = new Error("Cannot find module \"./locale\""); e.code = 'MODULE_NOT_FOUND'; throw e; }()); + // because defineLocale currently also sets the global locale, we want to undo that for lazy loaded locales + moment.locale(oldLocale); + } catch (e) { } + } + return locales[name]; + } + // Return a moment from input, that is local/utc/zone equivalent to model. function makeAs(input, model) { return model._isUTC ? moment(input).zone(model._offset || 0) : @@ -2072,11 +2193,11 @@ return /******/ (function(modules) { // webpackBootstrap } /************************************ - Languages + Locale ************************************/ - extend(Language.prototype, { + extend(Locale.prototype, { set : function (config) { var prop, i; @@ -2090,12 +2211,12 @@ return /******/ (function(modules) { // webpackBootstrap } }, - _months : "January_February_March_April_May_June_July_August_September_October_November_December".split("_"), + _months : 'January_February_March_April_May_June_July_August_September_October_November_December'.split('_'), months : function (m) { return this._months[m.month()]; }, - _monthsShort : "Jan_Feb_Mar_Apr_May_Jun_Jul_Aug_Sep_Oct_Nov_Dec".split("_"), + _monthsShort : 'Jan_Feb_Mar_Apr_May_Jun_Jul_Aug_Sep_Oct_Nov_Dec'.split('_'), monthsShort : function (m) { return this._monthsShort[m.month()]; }, @@ -2121,17 +2242,17 @@ return /******/ (function(modules) { // webpackBootstrap } }, - _weekdays : "Sunday_Monday_Tuesday_Wednesday_Thursday_Friday_Saturday".split("_"), + _weekdays : 'Sunday_Monday_Tuesday_Wednesday_Thursday_Friday_Saturday'.split('_'), weekdays : function (m) { return this._weekdays[m.day()]; }, - _weekdaysShort : "Sun_Mon_Tue_Wed_Thu_Fri_Sat".split("_"), + _weekdaysShort : 'Sun_Mon_Tue_Wed_Thu_Fri_Sat'.split('_'), weekdaysShort : function (m) { return this._weekdaysShort[m.day()]; }, - _weekdaysMin : "Su_Mo_Tu_We_Th_Fr_Sa".split("_"), + _weekdaysMin : 'Su_Mo_Tu_We_Th_Fr_Sa'.split('_'), weekdaysMin : function (m) { return this._weekdaysMin[m.day()]; }, @@ -2158,11 +2279,11 @@ return /******/ (function(modules) { // webpackBootstrap }, _longDateFormat : { - LT : "h:mm A", - L : "MM/DD/YYYY", - LL : "MMMM D YYYY", - LLL : "MMMM D YYYY LT", - LLLL : "dddd, MMMM D YYYY LT" + LT : 'h:mm A', + L : 'MM/DD/YYYY', + LL : 'MMMM D, YYYY', + LLL : 'MMMM D, YYYY LT', + LLLL : 'dddd, MMMM D, YYYY LT' }, longDateFormat : function (key) { var output = this._longDateFormat[key]; @@ -2204,35 +2325,37 @@ return /******/ (function(modules) { // webpackBootstrap }, _relativeTime : { - future : "in %s", - past : "%s ago", - s : "a few seconds", - m : "a minute", - mm : "%d minutes", - h : "an hour", - hh : "%d hours", - d : "a day", - dd : "%d days", - M : "a month", - MM : "%d months", - y : "a year", - yy : "%d years" + future : 'in %s', + past : '%s ago', + s : 'a few seconds', + m : 'a minute', + mm : '%d minutes', + h : 'an hour', + hh : '%d hours', + d : 'a day', + dd : '%d days', + M : 'a month', + MM : '%d months', + y : 'a year', + yy : '%d years' }, + relativeTime : function (number, withoutSuffix, string, isFuture) { var output = this._relativeTime[string]; return (typeof output === 'function') ? output(number, withoutSuffix, string, isFuture) : output.replace(/%d/i, number); }, + pastFuture : function (diff, output) { var format = this._relativeTime[diff > 0 ? 'future' : 'past']; return typeof format === 'function' ? format(output) : format.replace(/%s/i, output); }, ordinal : function (number) { - return this._ordinal.replace("%d", number); + return this._ordinal.replace('%d', number); }, - _ordinal : "%d", + _ordinal : '%d', preparse : function (string) { return string; @@ -2257,78 +2380,6 @@ return /******/ (function(modules) { // webpackBootstrap } }); - // Loads a language definition into the `languages` cache. The function - // takes a key and optionally values. If not in the browser and no values - // are provided, it will load the language file module. As a convenience, - // this function also returns the language values. - function loadLang(key, values) { - values.abbr = key; - if (!languages[key]) { - languages[key] = new Language(); - } - languages[key].set(values); - return languages[key]; - } - - // Remove a language from the `languages` cache. Mostly useful in tests. - function unloadLang(key) { - delete languages[key]; - } - - // Determines which language definition to use and returns it. - // - // With no parameters, it will return the global language. If you - // pass in a language key, such as 'en', it will return the - // definition for 'en', so long as 'en' has already been loaded using - // moment.lang. - function getLangDefinition(key) { - var i = 0, j, lang, next, split, - get = function (k) { - if (!languages[k] && hasModule) { - try { - __webpack_require__(4)("./" + k); - } catch (e) { } - } - return languages[k]; - }; - - if (!key) { - return moment.fn._lang; - } - - if (!isArray(key)) { - //short-circuit everything else - lang = get(key); - if (lang) { - return lang; - } - key = [key]; - } - - //pick the language from the array - //try ['en-au', 'en-gb'] as 'en-au', 'en-gb', 'en', as in move through the list trying each - //substring from most specific to least, but move to the next array item if it's a more specific variant than the current root - while (i < key.length) { - split = normalizeLanguage(key[i]).split('-'); - j = split.length; - next = normalizeLanguage(key[i + 1]); - next = next ? next.split('-') : null; - while (j > 0) { - lang = get(split.slice(0, j).join('-')); - if (lang) { - return lang; - } - if (next && next.length >= j && compareArrays(split, next, true) >= j - 1) { - //the next array item is better than a shallower substring of this one - break; - } - j--; - } - i++; - } - return moment.fn._lang; - } - /************************************ Formatting ************************************/ @@ -2336,9 +2387,9 @@ return /******/ (function(modules) { // webpackBootstrap function removeFormattingTokens(input) { if (input.match(/\[[\s\S]/)) { - return input.replace(/^\[|\]$/g, ""); + return input.replace(/^\[|\]$/g, ''); } - return input.replace(/\\/g, ""); + return input.replace(/\\/g, ''); } function makeFormatFunction(format) { @@ -2353,7 +2404,7 @@ return /******/ (function(modules) { // webpackBootstrap } return function (mom) { - var output = ""; + var output = ''; for (i = 0; i < length; i++) { output += array[i] instanceof Function ? array[i].call(mom, format) : array[i]; } @@ -2363,12 +2414,11 @@ return /******/ (function(modules) { // webpackBootstrap // format date using native date object function formatMoment(m, format) { - if (!m.isValid()) { - return m.lang().invalidDate(); + return m.localeData().invalidDate(); } - format = expandFormat(format, m.lang()); + format = expandFormat(format, m.localeData()); if (!formatFunctions[format]) { formatFunctions[format] = makeFormatFunction(format); @@ -2377,11 +2427,11 @@ return /******/ (function(modules) { // webpackBootstrap return formatFunctions[format](m); } - function expandFormat(format, lang) { + function expandFormat(format, locale) { var i = 5; function replaceLongDateFormatTokens(input) { - return lang.longDateFormat(input) || input; + return locale.longDateFormat(input) || input; } localFormattingTokens.lastIndex = 0; @@ -2422,13 +2472,19 @@ return /******/ (function(modules) { // webpackBootstrap case 'ggggg': return strict ? parseTokenSixDigits : parseTokenOneToSixDigits; case 'S': - if (strict) { return parseTokenOneDigit; } + if (strict) { + return parseTokenOneDigit; + } /* falls through */ case 'SS': - if (strict) { return parseTokenTwoDigits; } + if (strict) { + return parseTokenTwoDigits; + } /* falls through */ case 'SSS': - if (strict) { return parseTokenThreeDigits; } + if (strict) { + return parseTokenThreeDigits; + } /* falls through */ case 'DDD': return parseTokenOneToThreeDigits; @@ -2440,7 +2496,7 @@ return /******/ (function(modules) { // webpackBootstrap return parseTokenWord; case 'a': case 'A': - return getLangDefinition(config._l)._meridiemParse; + return config._locale._meridiemParse; case 'X': return parseTokenTimestampMs; case 'Z': @@ -2477,13 +2533,13 @@ return /******/ (function(modules) { // webpackBootstrap case 'Do': return parseTokenOrdinal; default : - a = new RegExp(regexpEscape(unescapeFormat(token.replace('\\', '')), "i")); + a = new RegExp(regexpEscape(unescapeFormat(token.replace('\\', '')), 'i')); return a; } } function timezoneMinutesFromString(string) { - string = string || ""; + string = string || ''; var possibleTzMatches = (string.match(parseTokenTimezone) || []), tzChunk = possibleTzMatches[possibleTzMatches.length - 1] || [], parts = (tzChunk + '').match(parseTimezoneChunker) || ['-', 0, 0], @@ -2512,7 +2568,7 @@ return /******/ (function(modules) { // webpackBootstrap break; case 'MMM' : // fall through to MMMM case 'MMMM' : - a = getLangDefinition(config._l).monthsParse(input); + a = config._locale.monthsParse(input); // if we didn't find a month name, mark the date as invalid. if (a != null) { datePartArray[MONTH] = a; @@ -2552,7 +2608,7 @@ return /******/ (function(modules) { // webpackBootstrap // AM / PM case 'a' : // fall through to A case 'A' : - config._isPm = getLangDefinition(config._l).isPM(input); + config._isPm = config._locale.isPM(input); break; // 24 HOUR case 'H' : // fall through to hh @@ -2592,7 +2648,7 @@ return /******/ (function(modules) { // webpackBootstrap case 'dd': case 'ddd': case 'dddd': - a = getLangDefinition(config._l).weekdaysParse(input); + a = config._locale.weekdaysParse(input); // if we didn't get a weekday name, mark the date as invalid if (a != null) { config._w = config._w || {}; @@ -2628,7 +2684,7 @@ return /******/ (function(modules) { // webpackBootstrap } function dayOfYearFromWeekInfo(config) { - var w, weekYear, week, weekday, dow, doy, temp, lang; + var w, weekYear, week, weekday, dow, doy, temp; w = config._w; if (w.GG != null || w.W != null || w.E != null) { @@ -2643,9 +2699,8 @@ return /******/ (function(modules) { // webpackBootstrap week = dfl(w.W, 1); weekday = dfl(w.E, 1); } else { - lang = getLangDefinition(config._l); - dow = lang._week.dow; - doy = lang._week.doy; + dow = config._locale._week.dow; + doy = config._locale._week.doy; weekYear = dfl(w.gg, config._a[YEAR], weekOfYear(moment(), dow, doy).year); week = dfl(w.w, 1); @@ -2759,7 +2814,6 @@ return /******/ (function(modules) { // webpackBootstrap // date from string and format string function makeDateFromStringAndFormat(config) { - if (config._f === moment.ISO_8601) { parseISO(config); return; @@ -2769,13 +2823,12 @@ return /******/ (function(modules) { // webpackBootstrap config._pf.empty = true; // This array is used to make a Date, either with `new Date` or `Date.UTC` - var lang = getLangDefinition(config._l), - string = '' + config._i, + var string = '' + config._i, i, parsedInput, tokens, token, skipped, stringLength = string.length, totalParsedInputLength = 0; - tokens = expandFormat(config._f, lang).match(formattingTokens) || []; + tokens = expandFormat(config._f, config._locale).match(formattingTokens) || []; for (i = 0; i < tokens.length; i++) { token = tokens[i]; @@ -2850,7 +2903,7 @@ return /******/ (function(modules) { // webpackBootstrap for (i = 0; i < config._f.length; i++) { currentScore = 0; - tempConfig = extend({}, config); + tempConfig = copyConfig({}, config); tempConfig._pf = defaultParsingFlags(); tempConfig._f = config._f[i]; makeDateFromStringAndFormat(tempConfig); @@ -2887,7 +2940,7 @@ return /******/ (function(modules) { // webpackBootstrap 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] + (match[6] || ' '); break; } } @@ -2898,7 +2951,7 @@ return /******/ (function(modules) { // webpackBootstrap } } if (string.match(parseTokenTimezone)) { - config._f += "Z"; + config._f += 'Z'; } makeDateFromStringAndFormat(config); } else { @@ -2916,20 +2969,18 @@ return /******/ (function(modules) { // webpackBootstrap } function makeDateFromInput(config) { - var input = config._i, - matched = aspNetJsonRegex.exec(input); - + var input = config._i, matched; if (input === undefined) { config._d = new Date(); - } else if (matched) { + } else if (isDate(input)) { + config._d = new Date(+input); + } else if ((matched = aspNetJsonRegex.exec(input)) !== null) { config._d = new Date(+matched[1]); } else if (typeof input === 'string') { makeDateFromString(config); } else if (isArray(input)) { config._a = input.slice(0); dateFromConfig(config); - } else if (isDate(input)) { - config._d = new Date(+input); } else if (typeof(input) === 'object') { dateFromObject(config); } else if (typeof(input) === 'number') { @@ -2960,13 +3011,13 @@ return /******/ (function(modules) { // webpackBootstrap return date; } - function parseWeekday(input, language) { + function parseWeekday(input, locale) { if (typeof input === 'string') { if (!isNaN(input)) { input = parseInt(input, 10); } else { - input = language.weekdaysParse(input); + input = locale.weekdaysParse(input); if (typeof input !== 'number') { return null; } @@ -2981,29 +3032,33 @@ return /******/ (function(modules) { // webpackBootstrap // helper function for moment.fn.from, moment.fn.fromNow, and moment.duration.fn.humanize - function substituteTimeAgo(string, number, withoutSuffix, isFuture, lang) { - return lang.relativeTime(number || 1, !!withoutSuffix, string, isFuture); + function substituteTimeAgo(string, number, withoutSuffix, isFuture, locale) { + return locale.relativeTime(number || 1, !!withoutSuffix, string, isFuture); } - function relativeTime(milliseconds, withoutSuffix, lang) { - var seconds = round(Math.abs(milliseconds) / 1000), - minutes = round(seconds / 60), - hours = round(minutes / 60), - days = round(hours / 24), - years = round(days / 365), - args = seconds < relativeTimeThresholds.s && ['s', seconds] || + function relativeTime(posNegDuration, withoutSuffix, locale) { + var duration = moment.duration(posNegDuration).abs(), + seconds = round(duration.as('s')), + minutes = round(duration.as('m')), + hours = round(duration.as('h')), + days = round(duration.as('d')), + months = round(duration.as('M')), + years = round(duration.as('y')), + + args = seconds < relativeTimeThresholds.s && ['s', seconds] || minutes === 1 && ['m'] || minutes < relativeTimeThresholds.m && ['mm', minutes] || hours === 1 && ['h'] || hours < relativeTimeThresholds.h && ['hh', hours] || days === 1 && ['d'] || - days <= relativeTimeThresholds.dd && ['dd', days] || - days <= relativeTimeThresholds.dm && ['M'] || - days < relativeTimeThresholds.dy && ['MM', round(days / 30)] || + days < relativeTimeThresholds.d && ['dd', days] || + months === 1 && ['M'] || + months < relativeTimeThresholds.M && ['MM', months] || years === 1 && ['y'] || ['yy', years]; + args[2] = withoutSuffix; - args[3] = milliseconds > 0; - args[4] = lang; + args[3] = +posNegDuration > 0; + args[4] = locale; return substituteTimeAgo.apply({}, args); } @@ -3034,7 +3089,7 @@ return /******/ (function(modules) { // webpackBootstrap daysToDayOfWeek += 7; } - adjustedMoment = moment(mom).add('d', daysToDayOfWeek); + adjustedMoment = moment(mom).add(daysToDayOfWeek, 'd'); return { week: Math.ceil(adjustedMoment.dayOfYear() / 7), year: adjustedMoment.year() @@ -3064,18 +3119,18 @@ return /******/ (function(modules) { // webpackBootstrap var input = config._i, format = config._f; + config._locale = config._locale || moment.localeData(config._l); + if (input === null || (format === undefined && input === '')) { return moment.invalid({nullInput: true}); } if (typeof input === 'string') { - config._i = input = getLangDefinition().preparse(input); + config._i = input = config._locale.preparse(input); } if (moment.isMoment(input)) { - config = cloneMoment(input); - - config._d = new Date(+input._d); + return new Moment(input, true); } else if (format) { if (isArray(format)) { makeDateFromStringAndArray(config); @@ -3089,12 +3144,12 @@ return /******/ (function(modules) { // webpackBootstrap return new Moment(config); } - moment = function (input, format, lang, strict) { + moment = function (input, format, locale, strict) { var c; - if (typeof(lang) === "boolean") { - strict = lang; - lang = undefined; + if (typeof(locale) === "boolean") { + strict = locale; + locale = undefined; } // object construction must be done this way. // https://github.com/moment/moment/issues/1423 @@ -3102,7 +3157,7 @@ return /******/ (function(modules) { // webpackBootstrap c._isAMomentObject = true; c._i = input; c._f = format; - c._l = lang; + c._l = locale; c._strict = strict; c._isUTC = false; c._pf = defaultParsingFlags(); @@ -3113,13 +3168,14 @@ return /******/ (function(modules) { // webpackBootstrap moment.suppressDeprecationWarnings = false; moment.createFromInputFallback = deprecate( - "moment construction falls back to js Date. This is " + - "discouraged and will be removed in upcoming major " + - "release. Please refer to " + - "https://github.com/moment/moment/issues/1407 for more info.", - function (config) { - config._d = new Date(config._i); - }); + 'moment construction falls back to js Date. This is ' + + 'discouraged and will be removed in upcoming major ' + + 'release. Please refer to ' + + 'https://github.com/moment/moment/issues/1407 for more info.', + function (config) { + config._d = new Date(config._i); + } + ); // Pick a moment m from moments so that m[fn](other) is true for all // other. This relies on the function fn to be transitive. @@ -3156,12 +3212,12 @@ return /******/ (function(modules) { // webpackBootstrap }; // creating with utc - moment.utc = function (input, format, lang, strict) { + moment.utc = function (input, format, locale, strict) { var c; - if (typeof(lang) === "boolean") { - strict = lang; - lang = undefined; + if (typeof(locale) === "boolean") { + strict = locale; + locale = undefined; } // object construction must be done this way. // https://github.com/moment/moment/issues/1423 @@ -3169,7 +3225,7 @@ return /******/ (function(modules) { // webpackBootstrap c._isAMomentObject = true; c._useUTC = true; c._isUTC = true; - c._l = lang; + c._l = locale; c._i = input; c._f = format; c._strict = strict; @@ -3190,7 +3246,8 @@ return /******/ (function(modules) { // webpackBootstrap match = null, sign, ret, - parseIso; + parseIso, + diffRes; if (moment.isDuration(input)) { duration = { @@ -3206,7 +3263,7 @@ return /******/ (function(modules) { // webpackBootstrap duration.milliseconds = input; } } else if (!!(match = aspNetTimeSpanJsonRegex.exec(input))) { - sign = (match[1] === "-") ? -1 : 1; + sign = (match[1] === '-') ? -1 : 1; duration = { y: 0, d: toInt(match[DATE]) * sign, @@ -3216,7 +3273,7 @@ return /******/ (function(modules) { // webpackBootstrap ms: toInt(match[MILLISECOND]) * sign }; } else if (!!(match = isoDurationRegex.exec(input))) { - sign = (match[1] === "-") ? -1 : 1; + sign = (match[1] === '-') ? -1 : 1; parseIso = function (inp) { // We'd normally use ~~inp for this, but unfortunately it also // converts floats to ints. @@ -3234,12 +3291,19 @@ return /******/ (function(modules) { // webpackBootstrap s: parseIso(match[7]), w: parseIso(match[8]) }; + } else if (typeof duration === 'object' && + ('from' in duration || 'to' in duration)) { + diffRes = momentsDifference(moment(duration.from), moment(duration.to)); + + duration = {}; + duration.ms = diffRes.milliseconds; + duration.M = diffRes.months; } ret = new Duration(duration); - if (moment.isDuration(input) && input.hasOwnProperty('_lang')) { - ret._lang = input._lang; + if (moment.isDuration(input) && input.hasOwnProperty('_locale')) { + ret._locale = input._locale; } return ret; @@ -3263,40 +3327,93 @@ return /******/ (function(modules) { // webpackBootstrap moment.updateOffset = function () {}; // This function allows you to set a threshold for relative time strings - moment.relativeTimeThreshold = function(threshold, limit) { - if (relativeTimeThresholds[threshold] === undefined) { - return false; - } - relativeTimeThresholds[threshold] = limit; - return true; + moment.relativeTimeThreshold = function (threshold, limit) { + if (relativeTimeThresholds[threshold] === undefined) { + return false; + } + if (limit === undefined) { + return relativeTimeThresholds[threshold]; + } + relativeTimeThresholds[threshold] = limit; + return true; }; - // This function will load languages and then set the global language. If + moment.lang = deprecate( + "moment.lang is deprecated. Use moment.locale instead.", + function (key, value) { + return moment.locale(key, value); + } + ); + + // This function will load locale and then set the global locale. If // no arguments are passed in, it will simply return the current global - // language key. - moment.lang = function (key, values) { - var r; - if (!key) { - return moment.fn._lang._abbr; - } - if (values) { - loadLang(normalizeLanguage(key), values); - } else if (values === null) { - unloadLang(key); - key = 'en'; - } else if (!languages[key]) { - getLangDefinition(key); - } - r = moment.duration.fn._lang = moment.fn._lang = getLangDefinition(key); - return r._abbr; + // locale key. + moment.locale = function (key, values) { + var data; + if (key) { + if (typeof(values) !== "undefined") { + data = moment.defineLocale(key, values); + } + else { + data = moment.localeData(key); + } + + if (data) { + moment.duration._locale = moment._locale = data; + } + } + + return moment._locale._abbr; + }; + + moment.defineLocale = function (name, values) { + if (values !== null) { + values.abbr = name; + if (!locales[name]) { + locales[name] = new Locale(); + } + locales[name].set(values); + + // backwards compat for now: also set the locale + moment.locale(name); + + return locales[name]; + } else { + // useful for testing + delete locales[name]; + return null; + } }; - // returns language data - moment.langData = function (key) { - if (key && key._lang && key._lang._abbr) { - key = key._lang._abbr; + moment.langData = deprecate( + "moment.langData is deprecated. Use moment.localeData instead.", + function (key) { + return moment.localeData(key); } - return getLangDefinition(key); + ); + + // returns locale data + moment.localeData = function (key) { + var locale; + + if (key && key._locale && key._locale._abbr) { + key = key._locale._abbr; + } + + if (!key) { + return moment._locale; + } + + if (!isArray(key)) { + //short-circuit everything else + locale = loadLocale(key); + if (locale) { + return locale; + } + key = [key]; + } + + return chooseLocale(key); }; // compare moment object @@ -3358,7 +3475,7 @@ return /******/ (function(modules) { // webpackBootstrap }, toString : function () { - return this.clone().lang('en').format("ddd MMM DD YYYY HH:mm:ss [GMT]ZZ"); + return this.clone().locale('en').format("ddd MMM DD YYYY HH:mm:ss [GMT]ZZ"); }, toDate : function () { @@ -3392,7 +3509,6 @@ return /******/ (function(modules) { // webpackBootstrap }, isDSTShifted : function () { - if (this._a) { return this.isValid() && compareArrays(this._a, (this._isUTC ? moment.utc(this._a) : moment(this._a)).toArray()) > 0; } @@ -3408,48 +3524,30 @@ return /******/ (function(modules) { // webpackBootstrap return this._pf.overflow; }, - utc : function () { - return this.zone(0); + utc : function (keepLocalTime) { + return this.zone(0, keepLocalTime); }, - local : function () { - this.zone(0); - this._isUTC = false; + local : function (keepLocalTime) { + if (this._isUTC) { + this.zone(0, keepLocalTime); + this._isUTC = false; + + if (keepLocalTime) { + this.add(this._d.getTimezoneOffset(), 'm'); + } + } return this; }, format : function (inputString) { var output = formatMoment(this, inputString || moment.defaultFormat); - return this.lang().postformat(output); + return this.localeData().postformat(output); }, - add : function (input, val) { - var dur; - // switch args to support add('s', 1) and add(1, 's') - if (typeof input === 'string' && typeof val === 'string') { - dur = moment.duration(isNaN(+val) ? +input : +val, isNaN(+val) ? val : input); - } else if (typeof input === 'string') { - dur = moment.duration(+val, input); - } else { - dur = moment.duration(input, val); - } - addOrSubtractDurationFromMoment(this, dur, 1); - return this; - }, + add : createAdder(1, 'add'), - subtract : function (input, val) { - var dur; - // switch args to support subtract('s', 1) and subtract(1, 's') - if (typeof input === 'string' && typeof val === 'string') { - dur = moment.duration(isNaN(+val) ? +input : +val, isNaN(+val) ? val : input); - } else if (typeof input === 'string') { - dur = moment.duration(+val, input); - } else { - dur = moment.duration(input, val); - } - addOrSubtractDurationFromMoment(this, dur, -1); - return this; - }, + subtract : createAdder(-1, 'subtract'), diff : function (input, units, asFloat) { var that = makeAs(input, this), @@ -3486,7 +3584,7 @@ return /******/ (function(modules) { // webpackBootstrap }, from : function (time, withoutSuffix) { - return moment.duration(this.diff(time)).lang(this.lang()._abbr).humanize(!withoutSuffix); + return moment.duration({to: this, from: time}).locale(this.locale()).humanize(!withoutSuffix); }, fromNow : function (withoutSuffix) { @@ -3505,7 +3603,7 @@ return /******/ (function(modules) { // webpackBootstrap diff < 1 ? 'sameDay' : diff < 2 ? 'nextDay' : diff < 7 ? 'nextWeek' : 'sameElse'; - return this.format(this.lang().calendar(format, this)); + return this.format(this.localeData().calendar(format, this)); }, isLeapYear : function () { @@ -3520,8 +3618,8 @@ return /******/ (function(modules) { // webpackBootstrap day : function (input) { var day = this._isUTC ? this._d.getUTCDay() : this._d.getDay(); if (input != null) { - input = parseWeekday(input, this.lang()); - return this.add({ d : input - day }); + input = parseWeekday(input, this.localeData()); + return this.add(input - day, 'd'); } else { return day; } @@ -3529,7 +3627,7 @@ return /******/ (function(modules) { // webpackBootstrap month : makeAccessor('Month', true), - startOf: function (units) { + startOf : function (units) { units = normalizeUnits(units); // the following switch intentionally omits break keywords // to utilize falling through the cases. @@ -3574,7 +3672,7 @@ return /******/ (function(modules) { // webpackBootstrap endOf: function (units) { units = normalizeUnits(units); - return this.startOf(units).add((units === 'isoWeek' ? 'week' : units), 1).subtract('ms', 1); + return this.startOf(units).add(1, (units === 'isoWeek' ? 'week' : units)).subtract(1, 'ms'); }, isAfter: function (input, units) { @@ -3593,7 +3691,7 @@ return /******/ (function(modules) { // webpackBootstrap }, min: deprecate( - "moment().min is deprecated, use moment.min instead. https://github.com/moment/moment/issues/1548", + 'moment().min is deprecated, use moment.min instead. https://github.com/moment/moment/issues/1548', function (other) { other = moment.apply(null, arguments); return other < this ? this : other; @@ -3601,36 +3699,43 @@ return /******/ (function(modules) { // webpackBootstrap ), max: deprecate( - "moment().max is deprecated, use moment.max instead. https://github.com/moment/moment/issues/1548", + 'moment().max is deprecated, use moment.max instead. https://github.com/moment/moment/issues/1548', function (other) { other = moment.apply(null, arguments); return other > this ? this : other; } ), - // keepTime = true means only change the timezone, without affecting - // the local hour. So 5:31:26 +0300 --[zone(2, true)]--> 5:31:26 +0200 - // It is possible that 5:31:26 doesn't exist int zone +0200, so we - // adjust the time as needed, to be valid. + // keepLocalTime = true means only change the timezone, without + // affecting the local hour. So 5:31:26 +0300 --[zone(2, true)]--> + // 5:31:26 +0200 It is possible that 5:31:26 doesn't exist int zone + // +0200, so we adjust the time as needed, to be valid. // // Keeping the time actually adds/subtracts (one hour) // from the actual represented time. That is why we call updateOffset // a second time. In case it wants us to change the offset again // _changeInProgress == true case, then we have to adjust, because // there is no such time in the given timezone. - zone : function (input, keepTime) { - var offset = this._offset || 0; + zone : function (input, keepLocalTime) { + var offset = this._offset || 0, + localAdjust; if (input != null) { - if (typeof input === "string") { + if (typeof input === 'string') { input = timezoneMinutesFromString(input); } if (Math.abs(input) < 16) { input = input * 60; } + if (!this._isUTC && keepLocalTime) { + localAdjust = this._d.getTimezoneOffset(); + } this._offset = input; this._isUTC = true; + if (localAdjust != null) { + this.subtract(localAdjust, 'm'); + } if (offset !== input) { - if (!keepTime || this._changeInProgress) { + if (!keepLocalTime || this._changeInProgress) { addOrSubtractDurationFromMoment(this, moment.duration(offset - input, 'm'), 1, false); } else if (!this._changeInProgress) { @@ -3646,11 +3751,11 @@ return /******/ (function(modules) { // webpackBootstrap }, zoneAbbr : function () { - return this._isUTC ? "UTC" : ""; + return this._isUTC ? 'UTC' : ''; }, zoneName : function () { - return this._isUTC ? "Coordinated Universal Time" : ""; + return this._isUTC ? 'Coordinated Universal Time' : ''; }, parseZone : function () { @@ -3679,7 +3784,7 @@ return /******/ (function(modules) { // webpackBootstrap dayOfYear : function (input) { var dayOfYear = round((moment(this).startOf('day') - moment(this).startOf('year')) / 864e5) + 1; - return input == null ? dayOfYear : this.add("d", (input - dayOfYear)); + return input == null ? dayOfYear : this.add((input - dayOfYear), 'd'); }, quarter : function (input) { @@ -3687,28 +3792,28 @@ return /******/ (function(modules) { // webpackBootstrap }, weekYear : function (input) { - var year = weekOfYear(this, this.lang()._week.dow, this.lang()._week.doy).year; - return input == null ? year : this.add("y", (input - year)); + var year = weekOfYear(this, this.localeData()._week.dow, this.localeData()._week.doy).year; + return input == null ? year : this.add((input - year), 'y'); }, isoWeekYear : function (input) { var year = weekOfYear(this, 1, 4).year; - return input == null ? year : this.add("y", (input - year)); + return input == null ? year : this.add((input - year), 'y'); }, week : function (input) { - var week = this.lang().week(this); - return input == null ? week : this.add("d", (input - week) * 7); + var week = this.localeData().week(this); + return input == null ? week : this.add((input - week) * 7, 'd'); }, isoWeek : function (input) { var week = weekOfYear(this, 1, 4).week; - return input == null ? week : this.add("d", (input - week) * 7); + return input == null ? week : this.add((input - week) * 7, 'd'); }, weekday : function (input) { - var weekday = (this.day() + 7 - this.lang()._week.dow) % 7; - return input == null ? weekday : this.add("d", input - weekday); + var weekday = (this.day() + 7 - this.localeData()._week.dow) % 7; + return input == null ? weekday : this.add(input - weekday, 'd'); }, isoWeekday : function (input) { @@ -3723,7 +3828,7 @@ return /******/ (function(modules) { // webpackBootstrap }, weeksInYear : function () { - var weekInfo = this._lang._week; + var weekInfo = this.localeData()._week; return weeksInYear(this.year(), weekInfo.dow, weekInfo.doy); }, @@ -3740,16 +3845,32 @@ return /******/ (function(modules) { // webpackBootstrap return this; }, - // If passed a language key, it will set the language for this - // instance. Otherwise, it will return the language configuration + // If passed a locale key, it will set the locale for this + // instance. Otherwise, it will return the locale configuration // variables for this instance. - lang : function (key) { + locale : function (key) { if (key === undefined) { - return this._lang; + return this._locale._abbr; } else { - this._lang = getLangDefinition(key); + this._locale = moment.localeData(key); return this; } + }, + + lang : deprecate( + "moment().lang() is deprecated. Use moment().localeData() instead.", + function (key) { + if (key === undefined) { + return this.localeData(); + } else { + this._locale = moment.localeData(key); + return this; + } + } + ), + + localeData : function () { + return this._locale; } }); @@ -3758,7 +3879,7 @@ return /******/ (function(modules) { // webpackBootstrap // TODO: Move this out of here! if (typeof value === 'string') { - value = mom.lang().monthsParse(value); + value = mom.localeData().monthsParse(value); // TODO: Another silent failure? if (typeof value !== 'number') { return mom; @@ -3805,9 +3926,9 @@ return /******/ (function(modules) { // webpackBootstrap moment.fn.hour = moment.fn.hours = makeAccessor('Hours', true); // moment.fn.month is defined separately moment.fn.date = makeAccessor('Date', true); - moment.fn.dates = deprecate("dates accessor is deprecated. Use date instead.", makeAccessor('Date', true)); + moment.fn.dates = deprecate('dates accessor is deprecated. Use date instead.', makeAccessor('Date', true)); moment.fn.year = makeAccessor('FullYear', true); - moment.fn.years = deprecate("years accessor is deprecated. Use year instead.", makeAccessor('FullYear', true)); + moment.fn.years = deprecate('years accessor is deprecated. Use year instead.', makeAccessor('FullYear', true)); // add plural methods moment.fn.days = moment.fn.day; @@ -3824,6 +3945,17 @@ return /******/ (function(modules) { // webpackBootstrap ************************************/ + function daysToYears (days) { + // 400 years have 146097 days (taking into account leap year rules) + return days * 400 / 146097; + } + + function yearsToDays (years) { + // years * 365 + absRound(years / 4) - + // absRound(years / 100) + absRound(years / 400); + return years * 146097 / 400; + } + extend(moment.duration.fn = Duration.prototype, { _bubble : function () { @@ -3831,7 +3963,7 @@ return /******/ (function(modules) { // webpackBootstrap days = this._days, months = this._months, data = this._data, - seconds, minutes, hours, years; + seconds, minutes, hours, years = 0; // The following code bubbles up values, see the tests for // examples of what that means. @@ -3847,15 +3979,40 @@ return /******/ (function(modules) { // webpackBootstrap data.hours = hours % 24; days += absRound(hours / 24); - data.days = days % 30; + // Accurately convert days to years, assume start from year 0. + years = absRound(daysToYears(days)); + days -= absRound(yearsToDays(years)); + + // 30 days to a month + // TODO (iskren): Use anchor date (like 1st Jan) to compute this. months += absRound(days / 30); - data.months = months % 12; + days %= 30; + + // 12 months -> 1 year + years += absRound(months / 12); + months %= 12; - years = absRound(months / 12); + data.days = days; + data.months = months; data.years = years; }, + abs : function () { + this._milliseconds = Math.abs(this._milliseconds); + this._days = Math.abs(this._days); + this._months = Math.abs(this._months); + + this._data.milliseconds = Math.abs(this._data.milliseconds); + this._data.seconds = Math.abs(this._data.seconds); + this._data.minutes = Math.abs(this._data.minutes); + this._data.hours = Math.abs(this._data.hours); + this._data.months = Math.abs(this._data.months); + this._data.years = Math.abs(this._data.years); + + return this; + }, + weeks : function () { return absRound(this.days() / 7); }, @@ -3868,14 +4025,13 @@ return /******/ (function(modules) { // webpackBootstrap }, humanize : function (withSuffix) { - var difference = +this, - output = relativeTime(difference, !withSuffix, this.lang()); + var output = relativeTime(this, !withSuffix, this.localeData()); if (withSuffix) { - output = this.lang().pastFuture(difference, output); + output = this.localeData().pastFuture(+this, output); } - return this.lang().postformat(output); + return this.localeData().postformat(output); }, add : function (input, val) { @@ -3909,13 +4065,39 @@ return /******/ (function(modules) { // webpackBootstrap }, as : function (units) { + var days, months; units = normalizeUnits(units); - return this['as' + units.charAt(0).toUpperCase() + units.slice(1) + 's'](); + + days = this._days + this._milliseconds / 864e5; + if (units === 'month' || units === 'year') { + months = this._months + daysToYears(days) * 12; + return units === 'month' ? months : months / 12; + } else { + days += yearsToDays(this._months / 12); + switch (units) { + case 'week': return days / 7; + case 'day': return days; + case 'hour': return days * 24; + case 'minute': return days * 24 * 60; + case 'second': return days * 24 * 60 * 60; + case 'millisecond': return days * 24 * 60 * 60 * 1000; + default: throw new Error('Unknown unit ' + units); + } + } }, lang : moment.fn.lang, + locale : moment.fn.locale, + + toIsoString : deprecate( + "toIsoString() is deprecated. Please use toISOString() instead " + + "(notice the capitals)", + function () { + return this.toISOString(); + } + ), - toIsoString : function () { + toISOString : function () { // inspired by https://github.com/dordille/moment-isoduration/blob/master/moment.isoduration.js var years = Math.abs(this.years()), months = Math.abs(this.months()), @@ -3939,6 +4121,10 @@ return /******/ (function(modules) { // webpackBootstrap (hours ? hours + 'H' : '') + (minutes ? minutes + 'M' : '') + (seconds ? seconds + 'S' : ''); + }, + + localeData : function () { + return this._locale; } }); @@ -3948,32 +4134,44 @@ return /******/ (function(modules) { // webpackBootstrap }; } - function makeDurationAsGetter(name, factor) { - moment.duration.fn['as' + name] = function () { - return +this / factor; - }; - } - for (i in unitMillisecondFactors) { if (unitMillisecondFactors.hasOwnProperty(i)) { - makeDurationAsGetter(i, unitMillisecondFactors[i]); makeDurationGetter(i.toLowerCase()); } } - makeDurationAsGetter('Weeks', 6048e5); + moment.duration.fn.asMilliseconds = function () { + return this.as('ms'); + }; + moment.duration.fn.asSeconds = function () { + return this.as('s'); + }; + moment.duration.fn.asMinutes = function () { + return this.as('m'); + }; + moment.duration.fn.asHours = function () { + return this.as('h'); + }; + moment.duration.fn.asDays = function () { + return this.as('d'); + }; + moment.duration.fn.asWeeks = function () { + return this.as('weeks'); + }; moment.duration.fn.asMonths = function () { - return (+this - this.years() * 31536e6) / 2592e6 + this.years() * 12; + return this.as('M'); + }; + moment.duration.fn.asYears = function () { + return this.as('y'); }; - /************************************ - Default Lang + Default Locale ************************************/ - // Set default language, other languages will inherit from English. - moment.lang('en', { + // Set default locale, other locale will inherit from English. + moment.locale('en', { ordinal : function (number) { var b = number % 10, output = (toInt(number % 100 / 10) === 1) ? 'th' : @@ -3984,7 +4182,7 @@ return /******/ (function(modules) { // webpackBootstrap } }); - /* EMBED_LANGUAGES */ + /* EMBED_LOCALES */ /************************************ Exposing Moment @@ -3998,9 +4196,9 @@ return /******/ (function(modules) { // webpackBootstrap oldGlobalMoment = globalScope.moment; if (shouldDeprecate) { globalScope.moment = deprecate( - "Accessing Moment through the global scope is " + - "deprecated, and will be removed in an upcoming " + - "release.", + 'Accessing Moment through the global scope is ' + + 'deprecated, and will be removed in an upcoming ' + + 'release.', moment); } else { globalScope.moment = moment; @@ -4031,17 +4229,11 @@ return /******/ (function(modules) { // webpackBootstrap /* 4 */ /***/ function(module, exports, __webpack_require__) { - var map = {}; function webpackContext(req) { - return __webpack_require__(webpackContextResolve(req)); - }; - function webpackContextResolve(req) { - return map[req] || (function() { throw new Error("Cannot find module '" + req + "'.") }()); - }; - webpackContext.keys = function webpackContextKeys() { - return Object.keys(map); - }; - webpackContext.resolve = webpackContextResolve; + throw new Error("Cannot find module '" + req + "'."); + } + webpackContext.resolve = webpackContext; + webpackContext.keys = function() { return []; }; module.exports = webpackContext; @@ -8912,8 +9104,8 @@ return /******/ (function(modules) { // webpackBootstrap var Core = __webpack_require__(23); var TimeAxis = __webpack_require__(24); var CurrentTime = __webpack_require__(26); - var CustomTime = __webpack_require__(27); - var ItemSet = __webpack_require__(28); + var CustomTime = __webpack_require__(28); + var ItemSet = __webpack_require__(29); /** * Create a timeline visualization @@ -12016,8 +12208,8 @@ return /******/ (function(modules) { // webpackBootstrap var Range = __webpack_require__(20); var TimeAxis = __webpack_require__(24); var CurrentTime = __webpack_require__(26); - var CustomTime = __webpack_require__(27); - var ItemSet = __webpack_require__(28); + var CustomTime = __webpack_require__(28); + var ItemSet = __webpack_require__(29); /** * Create a timeline visualization @@ -12679,6 +12871,7 @@ return /******/ (function(modules) { // webpackBootstrap var util = __webpack_require__(1); var Component = __webpack_require__(22); var TimeStep = __webpack_require__(25); + var moment = __webpack_require__(2); /** * A horizontal time axis @@ -12741,6 +12934,18 @@ return /******/ (function(modules) { // webpackBootstrap if (options) { // copy all options that we know util.selectiveExtend(['orientation', 'showMinorLabels', 'showMajorLabels'], this.options, options); + + // apply locale to moment.js + // TODO: not so nice, this is applied globally to moment.js + if ('locale' in options) { + if (typeof moment.locale === 'function') { + // moment.js 2.8.1+ + moment.locale(options.locale); + } + else { + moment.lang(options.locale); + } + } } }; @@ -13555,6 +13760,8 @@ return /******/ (function(modules) { // webpackBootstrap var util = __webpack_require__(1); var Component = __webpack_require__(22); + var moment = __webpack_require__(2); + var locales = __webpack_require__(27); /** * A current time bar @@ -13569,7 +13776,10 @@ return /******/ (function(modules) { // webpackBootstrap // default options this.defaultOptions = { - showCurrentTime: true + showCurrentTime: true, + + locales: locales, + locale: 'en' }; this.options = util.extend({}, this.defaultOptions); @@ -13612,7 +13822,7 @@ return /******/ (function(modules) { // webpackBootstrap CurrentTime.prototype.setOptions = function(options) { if (options) { // copy all options that we know - util.selectiveExtend(['showCurrentTime'], this.options, options); + util.selectiveExtend(['showCurrentTime', 'locale', 'locales'], this.options, options); } }; @@ -13636,8 +13846,12 @@ return /******/ (function(modules) { // webpackBootstrap var now = new Date(); var x = this.body.util.toScreen(now); + var locale = this.options.locales[this.options.locale]; + var title = locale.current + ' ' + locale.time + ': ' + moment(now).format('dddd, MMMM Do YYYY, H:mm:ss'); + title = title.charAt(0).toUpperCase() + title.substring(1); + this.bar.style.left = x + 'px'; - this.bar.title = 'Current time: ' + now; + this.bar.title = title; } else { // remove the line from the DOM @@ -13689,11 +13903,34 @@ return /******/ (function(modules) { // webpackBootstrap /***/ }, /* 27 */ +/***/ function(module, exports, __webpack_require__) { + + // English + exports['en'] = { + current: 'current', + time: 'time' + }; + exports['en_EN'] = exports['en']; + exports['en_US'] = exports['en']; + + // Dutch + exports['nl'] = { + custom: 'aangepaste', + time: 'tijd' + }; + exports['nl_NL'] = exports['nl']; + exports['nl_BE'] = exports['nl']; + + +/***/ }, +/* 28 */ /***/ function(module, exports, __webpack_require__) { var Hammer = __webpack_require__(18); var util = __webpack_require__(1); var Component = __webpack_require__(22); + var moment = __webpack_require__(2); + var locales = __webpack_require__(27); /** * A custom time bar @@ -13709,7 +13946,9 @@ return /******/ (function(modules) { // webpackBootstrap // default options this.defaultOptions = { - showCustomTime: false + showCustomTime: false, + locales: locales, + locale: 'en' }; this.options = util.extend({}, this.defaultOptions); @@ -13732,7 +13971,7 @@ return /******/ (function(modules) { // webpackBootstrap CustomTime.prototype.setOptions = function(options) { if (options) { // copy all options that we know - util.selectiveExtend(['showCustomTime'], this.options, options); + util.selectiveExtend(['showCustomTime', 'locale', 'locales'], this.options, options); } }; @@ -13795,8 +14034,12 @@ return /******/ (function(modules) { // webpackBootstrap var x = this.body.util.toScreen(this.customTime); + var locale = this.options.locales[this.options.locale]; + var title = locale.time + ': ' + moment(this.customTime).format('dddd, MMMM Do YYYY, H:mm:ss'); + title = title.charAt(0).toUpperCase() + title.substring(1); + this.bar.style.left = x + 'px'; - this.bar.title = 'Time: ' + this.customTime; + this.bar.title = title; } else { // remove the line from the DOM @@ -13882,7 +14125,7 @@ return /******/ (function(modules) { // webpackBootstrap /***/ }, -/* 28 */ +/* 29 */ /***/ function(module, exports, __webpack_require__) { var Hammer = __webpack_require__(18); @@ -13890,10 +14133,10 @@ return /******/ (function(modules) { // webpackBootstrap var DataSet = __webpack_require__(7); var DataView = __webpack_require__(8); var Component = __webpack_require__(22); - var Group = __webpack_require__(29); - var ItemBox = __webpack_require__(33); - var ItemPoint = __webpack_require__(34); - var ItemRange = __webpack_require__(31); + var Group = __webpack_require__(30); + var ItemBox = __webpack_require__(34); + var ItemPoint = __webpack_require__(35); + var ItemRange = __webpack_require__(32); var UNGROUPED = '__ungrouped__'; // reserved group id for ungrouped items @@ -15285,12 +15528,12 @@ return /******/ (function(modules) { // webpackBootstrap /***/ }, -/* 29 */ +/* 30 */ /***/ function(module, exports, __webpack_require__) { var util = __webpack_require__(1); - var stack = __webpack_require__(30); - var ItemRange = __webpack_require__(31); + var stack = __webpack_require__(31); + var ItemRange = __webpack_require__(32); /** * @constructor Group @@ -15715,7 +15958,7 @@ return /******/ (function(modules) { // webpackBootstrap /***/ }, -/* 30 */ +/* 31 */ /***/ function(module, exports, __webpack_require__) { // Utility functions for ordering and stacking of items @@ -15829,11 +16072,11 @@ return /******/ (function(modules) { // webpackBootstrap /***/ }, -/* 31 */ +/* 32 */ /***/ function(module, exports, __webpack_require__) { var Hammer = __webpack_require__(18); - var Item = __webpack_require__(32); + var Item = __webpack_require__(33); /** * @constructor ItemRange @@ -16125,7 +16368,7 @@ return /******/ (function(modules) { // webpackBootstrap /***/ }, -/* 32 */ +/* 33 */ /***/ function(module, exports, __webpack_require__) { var Hammer = __webpack_require__(18); @@ -16274,10 +16517,10 @@ return /******/ (function(modules) { // webpackBootstrap /***/ }, -/* 33 */ +/* 34 */ /***/ function(module, exports, __webpack_require__) { - var Item = __webpack_require__(32); + var Item = __webpack_require__(33); /** * @constructor ItemBox @@ -16520,10 +16763,10 @@ return /******/ (function(modules) { // webpackBootstrap /***/ }, -/* 34 */ +/* 35 */ /***/ function(module, exports, __webpack_require__) { - var Item = __webpack_require__(32); + var Item = __webpack_require__(33); /** * @constructor ItemPoint @@ -16726,7 +16969,7 @@ return /******/ (function(modules) { // webpackBootstrap /***/ }, -/* 35 */ +/* 36 */ /***/ function(module, exports, __webpack_require__) { var Emitter = __webpack_require__(10); @@ -16738,8 +16981,8 @@ return /******/ (function(modules) { // webpackBootstrap var Core = __webpack_require__(23); var TimeAxis = __webpack_require__(24); var CurrentTime = __webpack_require__(26); - var CustomTime = __webpack_require__(27); - var LineGraph = __webpack_require__(36); + var CustomTime = __webpack_require__(28); + var LineGraph = __webpack_require__(37); /** * Create a timeline visualization @@ -17017,7 +17260,7 @@ return /******/ (function(modules) { // webpackBootstrap /***/ }, -/* 36 */ +/* 37 */ /***/ function(module, exports, __webpack_require__) { var util = __webpack_require__(1); @@ -17025,9 +17268,9 @@ return /******/ (function(modules) { // webpackBootstrap var DataSet = __webpack_require__(7); var DataView = __webpack_require__(8); var Component = __webpack_require__(22); - var DataAxis = __webpack_require__(37); - var GraphGroup = __webpack_require__(38); - var Legend = __webpack_require__(39); + var DataAxis = __webpack_require__(38); + var GraphGroup = __webpack_require__(40); + var Legend = __webpack_require__(41); var UNGROUPED = '__ungrouped__'; // reserved group id for ungrouped items @@ -18153,13 +18396,13 @@ return /******/ (function(modules) { // webpackBootstrap /***/ }, -/* 37 */ +/* 38 */ /***/ function(module, exports, __webpack_require__) { var util = __webpack_require__(1); var DOMutil = __webpack_require__(6); var Component = __webpack_require__(22); - var DataStep = __webpack_require__(40); + var DataStep = __webpack_require__(39); /** * A horizontal time axis @@ -18658,7 +18901,233 @@ return /******/ (function(modules) { // webpackBootstrap /***/ }, -/* 38 */ +/* 39 */ +/***/ function(module, exports, __webpack_require__) { + + /** + * @constructor DataStep + * The class DataStep is an iterator for data for the lineGraph. You provide a start data point and an + * end data point. 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 DataStep 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 DataStep(start, end, minimumStep, containerHeight, customRange) { + // variables + this.current = 0; + + this.autoScale = true; + this.stepIndex = 0; + this.step = 1; + this.scale = 1; + + this.marginStart; + this.marginEnd; + this.deadSpace = 0; + + this.majorSteps = [1, 2, 5, 10]; + this.minorSteps = [0.25, 0.5, 1, 2]; + + this.setRange(start, end, minimumStep, containerHeight, customRange); + } + + + + /** + * 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 {Number} [start] The start date and time. + * @param {Number} [end] The end date and time. + * @param {Number} [minimumStep] Optional. Minimum step size in milliseconds + */ + DataStep.prototype.setRange = function(start, end, minimumStep, containerHeight, customRange) { + this._start = customRange.min === undefined ? start : customRange.min; + this._end = customRange.max === undefined ? end : customRange.max; + + if (start == end) { + this._start = start - 0.75; + this._end = end + 1; + } + + if (this.autoScale) { + this.setMinimumStep(minimumStep, containerHeight); + } + this.setFirst(customRange); + }; + + /** + * Automatically determine the scale that bests fits the provided minimum step + * @param {Number} [minimumStep] The minimum step size in milliseconds + */ + DataStep.prototype.setMinimumStep = function(minimumStep, containerHeight) { + // round to floor + var size = this._end - this._start; + var safeSize = size * 1.2; + var minimumStepValue = minimumStep * (safeSize / containerHeight); + var orderOfMagnitude = Math.round(Math.log(safeSize)/Math.LN10); + + var minorStepIdx = -1; + var magnitudefactor = Math.pow(10,orderOfMagnitude); + + var start = 0; + if (orderOfMagnitude < 0) { + start = orderOfMagnitude; + } + + var solutionFound = false; + for (var i = start; Math.abs(i) <= Math.abs(orderOfMagnitude); i++) { + magnitudefactor = Math.pow(10,i); + for (var j = 0; j < this.minorSteps.length; j++) { + var stepSize = magnitudefactor * this.minorSteps[j]; + if (stepSize >= minimumStepValue) { + solutionFound = true; + minorStepIdx = j; + break; + } + } + if (solutionFound == true) { + break; + } + } + this.stepIndex = minorStepIdx; + this.scale = magnitudefactor; + this.step = magnitudefactor * this.minorSteps[minorStepIdx]; + }; + + + + /** + * Round the current date to the first minor date value + * This must be executed once when the current date is set to start Date + */ + DataStep.prototype.setFirst = function(customRange) { + if (customRange === undefined) { + customRange = {}; + } + var niceStart = customRange.min === undefined ? this._start - (this.scale * 2 * this.minorSteps[this.stepIndex]) : customRange.min; + var niceEnd = customRange.max === undefined ? this._end + (this.scale * this.minorSteps[this.stepIndex]) : customRange.max; + + this.marginEnd = customRange.max === undefined ? this.roundToMinor(niceEnd) : customRange.max; + this.marginStart = customRange.min === undefined ? this.roundToMinor(niceStart) : customRange.min; + this.deadSpace = this.roundToMinor(niceEnd) - niceEnd + this.roundToMinor(niceStart) - niceStart; + this.marginRange = this.marginEnd - this.marginStart; + + this.current = this.marginEnd; + + }; + + DataStep.prototype.roundToMinor = function(value) { + var rounded = value - (value % (this.scale * this.minorSteps[this.stepIndex])); + if (value % (this.scale * this.minorSteps[this.stepIndex]) > 0.5 * (this.scale * this.minorSteps[this.stepIndex])) { + return rounded + (this.scale * this.minorSteps[this.stepIndex]); + } + else { + return rounded; + } + } + + + /** + * Check if the there is a next step + * @return {boolean} true if the current date has not passed the end date + */ + DataStep.prototype.hasNext = function () { + return (this.current >= this.marginStart); + }; + + /** + * Do the next step + */ + DataStep.prototype.next = function() { + var prev = this.current; + this.current -= this.step; + + // safety mechanism: if current time is still unchanged, move to the end + if (this.current == prev) { + this.current = this._end; + } + }; + + /** + * Do the next step + */ + DataStep.prototype.previous = function() { + this.current += this.step; + this.marginEnd += this.step; + this.marginRange = this.marginEnd - this.marginStart; + }; + + + + /** + * Get the current datetime + * @return {String} current The current date + */ + DataStep.prototype.getCurrent = function() { + var toPrecision = '' + Number(this.current).toPrecision(5); + for (var i = toPrecision.length-1; i > 0; i--) { + if (toPrecision[i] == "0") { + toPrecision = toPrecision.slice(0,i); + } + else if (toPrecision[i] == "." || toPrecision[i] == ",") { + toPrecision = toPrecision.slice(0,i); + break; + } + else{ + break; + } + } + + return toPrecision; + }; + + + + /** + * Snap a date to a rounded value. + * The snap intervals are dependent on the current scale and step. + * @param {Date} date the date to be snapped. + * @return {Date} snappedDate + */ + DataStep.prototype.snap = function(date) { + + }; + + /** + * Check if the current value is a major value (for example when the step + * is DAY, a major value is each first day of the MONTH) + * @return {boolean} true if current date is major, else false. + */ + DataStep.prototype.isMajor = function() { + return (this.current % (this.scale * this.majorSteps[this.stepIndex]) == 0); + }; + + module.exports = DataStep; + + +/***/ }, +/* 40 */ /***/ function(module, exports, __webpack_require__) { var util = __webpack_require__(1); @@ -18799,7 +19268,7 @@ return /******/ (function(modules) { // webpackBootstrap /***/ }, -/* 39 */ +/* 41 */ /***/ function(module, exports, __webpack_require__) { var util = __webpack_require__(1); @@ -19001,253 +19470,28 @@ return /******/ (function(modules) { // webpackBootstrap /***/ }, -/* 40 */ -/***/ function(module, exports, __webpack_require__) { - - /** - * @constructor DataStep - * The class DataStep is an iterator for data for the lineGraph. You provide a start data point and an - * end data point. 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 DataStep 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 DataStep(start, end, minimumStep, containerHeight, customRange) { - // variables - this.current = 0; - - this.autoScale = true; - this.stepIndex = 0; - this.step = 1; - this.scale = 1; - - this.marginStart; - this.marginEnd; - this.deadSpace = 0; - - this.majorSteps = [1, 2, 5, 10]; - this.minorSteps = [0.25, 0.5, 1, 2]; - - this.setRange(start, end, minimumStep, containerHeight, customRange); - } - - - - /** - * 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 {Number} [start] The start date and time. - * @param {Number} [end] The end date and time. - * @param {Number} [minimumStep] Optional. Minimum step size in milliseconds - */ - DataStep.prototype.setRange = function(start, end, minimumStep, containerHeight, customRange) { - this._start = customRange.min === undefined ? start : customRange.min; - this._end = customRange.max === undefined ? end : customRange.max; - - if (start == end) { - this._start = start - 0.75; - this._end = end + 1; - } - - if (this.autoScale) { - this.setMinimumStep(minimumStep, containerHeight); - } - this.setFirst(customRange); - }; - - /** - * Automatically determine the scale that bests fits the provided minimum step - * @param {Number} [minimumStep] The minimum step size in milliseconds - */ - DataStep.prototype.setMinimumStep = function(minimumStep, containerHeight) { - // round to floor - var size = this._end - this._start; - var safeSize = size * 1.2; - var minimumStepValue = minimumStep * (safeSize / containerHeight); - var orderOfMagnitude = Math.round(Math.log(safeSize)/Math.LN10); - - var minorStepIdx = -1; - var magnitudefactor = Math.pow(10,orderOfMagnitude); - - var start = 0; - if (orderOfMagnitude < 0) { - start = orderOfMagnitude; - } - - var solutionFound = false; - for (var i = start; Math.abs(i) <= Math.abs(orderOfMagnitude); i++) { - magnitudefactor = Math.pow(10,i); - for (var j = 0; j < this.minorSteps.length; j++) { - var stepSize = magnitudefactor * this.minorSteps[j]; - if (stepSize >= minimumStepValue) { - solutionFound = true; - minorStepIdx = j; - break; - } - } - if (solutionFound == true) { - break; - } - } - this.stepIndex = minorStepIdx; - this.scale = magnitudefactor; - this.step = magnitudefactor * this.minorSteps[minorStepIdx]; - }; - - - - /** - * Round the current date to the first minor date value - * This must be executed once when the current date is set to start Date - */ - DataStep.prototype.setFirst = function(customRange) { - if (customRange === undefined) { - customRange = {}; - } - var niceStart = customRange.min === undefined ? this._start - (this.scale * 2 * this.minorSteps[this.stepIndex]) : customRange.min; - var niceEnd = customRange.max === undefined ? this._end + (this.scale * this.minorSteps[this.stepIndex]) : customRange.max; - - this.marginEnd = customRange.max === undefined ? this.roundToMinor(niceEnd) : customRange.max; - this.marginStart = customRange.min === undefined ? this.roundToMinor(niceStart) : customRange.min; - this.deadSpace = this.roundToMinor(niceEnd) - niceEnd + this.roundToMinor(niceStart) - niceStart; - this.marginRange = this.marginEnd - this.marginStart; - - this.current = this.marginEnd; - - }; - - DataStep.prototype.roundToMinor = function(value) { - var rounded = value - (value % (this.scale * this.minorSteps[this.stepIndex])); - if (value % (this.scale * this.minorSteps[this.stepIndex]) > 0.5 * (this.scale * this.minorSteps[this.stepIndex])) { - return rounded + (this.scale * this.minorSteps[this.stepIndex]); - } - else { - return rounded; - } - } - - - /** - * Check if the there is a next step - * @return {boolean} true if the current date has not passed the end date - */ - DataStep.prototype.hasNext = function () { - return (this.current >= this.marginStart); - }; - - /** - * Do the next step - */ - DataStep.prototype.next = function() { - var prev = this.current; - this.current -= this.step; - - // safety mechanism: if current time is still unchanged, move to the end - if (this.current == prev) { - this.current = this._end; - } - }; - - /** - * Do the next step - */ - DataStep.prototype.previous = function() { - this.current += this.step; - this.marginEnd += this.step; - this.marginRange = this.marginEnd - this.marginStart; - }; - - - - /** - * Get the current datetime - * @return {String} current The current date - */ - DataStep.prototype.getCurrent = function() { - var toPrecision = '' + Number(this.current).toPrecision(5); - for (var i = toPrecision.length-1; i > 0; i--) { - if (toPrecision[i] == "0") { - toPrecision = toPrecision.slice(0,i); - } - else if (toPrecision[i] == "." || toPrecision[i] == ",") { - toPrecision = toPrecision.slice(0,i); - break; - } - else{ - break; - } - } - - return toPrecision; - }; - - - - /** - * Snap a date to a rounded value. - * The snap intervals are dependent on the current scale and step. - * @param {Date} date the date to be snapped. - * @return {Date} snappedDate - */ - DataStep.prototype.snap = function(date) { - - }; - - /** - * Check if the current value is a major value (for example when the step - * is DAY, a major value is each first day of the MONTH) - * @return {boolean} true if current date is major, else false. - */ - DataStep.prototype.isMajor = function() { - return (this.current % (this.scale * this.majorSteps[this.stepIndex]) == 0); - }; - - module.exports = DataStep; - - -/***/ }, -/* 41 */ +/* 42 */ /***/ function(module, exports, __webpack_require__) { var Emitter = __webpack_require__(10); var Hammer = __webpack_require__(18); - var mousetrap = __webpack_require__(42); + var mousetrap = __webpack_require__(43); var util = __webpack_require__(1); var hammerUtil = __webpack_require__(21); var DataSet = __webpack_require__(7); var DataView = __webpack_require__(8); - var dotparser = __webpack_require__(43); - var gephiParser = __webpack_require__(44); - var Groups = __webpack_require__(45); - var Images = __webpack_require__(46); - var Node = __webpack_require__(47); - var Edge = __webpack_require__(48); - var Popup = __webpack_require__(49); - var MixinLoader = __webpack_require__(50); + var dotparser = __webpack_require__(44); + var gephiParser = __webpack_require__(45); + var Groups = __webpack_require__(46); + var Images = __webpack_require__(47); + var Node = __webpack_require__(48); + var Edge = __webpack_require__(49); + var Popup = __webpack_require__(50); + var MixinLoader = __webpack_require__(51); + var locales = __webpack_require__(62); // Load custom shapes into CanvasRenderingContext2D - __webpack_require__(61); + __webpack_require__(63); /** * @constructor Network @@ -19420,24 +19664,8 @@ return /******/ (function(modules) { // webpackBootstrap minVelocity: 0.1, // px/s stabilize: true, // stabilize before displaying the network stabilizationIterations: 1000, // maximum number of iteration to stabilize - labels:{ - add:"Add Node", - edit:"Edit", - link:"Add Link", - del:"Delete selected", - editNode:"Edit Node", - editEdge:"Edit Edge", - back:"Back", - addDescription:"Click in an empty space to place a new node.", - linkDescription:"Click on a node and drag the edge to another node to connect them.", - editEdgeDescription:"Click on the control points and drag them to a node to connect to it.", - addError:"The function for add does not support two arguments (data,callback).", - linkError:"The function for connect does not support two arguments (data,callback).", - editError:"The function for edit does not support two arguments (data, callback).", - editBoundError:"No edit function has been bound to this button.", - deleteError:"The function for delete does not support two arguments (data, callback).", - deleteClusterError:"Clusters cannot be deleted." - }, + locale: 'en', + locales: locales, tooltip: { delay: 300, fontColor: 'black', @@ -19894,6 +20122,10 @@ return /******/ (function(modules) { // webpackBootstrap this.constants.tooltip.color = util.parseColor(options.tooltip.color); } } + + if (options.labels) { + throw new Error('Option "labels" is deprecated. Use options "locale" and "locales" instead.'); + } } // (Re)loading the mixins that can be enabled or disabled in the options. @@ -21480,7 +21712,7 @@ return /******/ (function(modules) { // webpackBootstrap /***/ }, -/* 42 */ +/* 43 */ /***/ function(module, exports, __webpack_require__) { /** @@ -22285,7 +22517,7 @@ return /******/ (function(modules) { // webpackBootstrap /***/ }, -/* 43 */ +/* 44 */ /***/ function(module, exports, __webpack_require__) { /** @@ -23117,7 +23349,7 @@ return /******/ (function(modules) { // webpackBootstrap /***/ }, -/* 44 */ +/* 45 */ /***/ function(module, exports, __webpack_require__) { @@ -23182,7 +23414,7 @@ return /******/ (function(modules) { // webpackBootstrap exports.parseGephi = parseGephi; /***/ }, -/* 45 */ +/* 46 */ /***/ function(module, exports, __webpack_require__) { var util = __webpack_require__(1); @@ -23271,7 +23503,7 @@ return /******/ (function(modules) { // webpackBootstrap /***/ }, -/* 46 */ +/* 47 */ /***/ function(module, exports, __webpack_require__) { /** @@ -23320,7 +23552,7 @@ return /******/ (function(modules) { // webpackBootstrap /***/ }, -/* 47 */ +/* 48 */ /***/ function(module, exports, __webpack_require__) { var util = __webpack_require__(1); @@ -24291,11 +24523,11 @@ return /******/ (function(modules) { // webpackBootstrap /***/ }, -/* 48 */ +/* 49 */ /***/ function(module, exports, __webpack_require__) { var util = __webpack_require__(1); - var Node = __webpack_require__(47); + var Node = __webpack_require__(48); /** * @class Edge @@ -25460,7 +25692,7 @@ return /******/ (function(modules) { // webpackBootstrap module.exports = Edge; /***/ }, -/* 49 */ +/* 50 */ /***/ function(module, exports, __webpack_require__) { /** @@ -25600,16 +25832,16 @@ return /******/ (function(modules) { // webpackBootstrap /***/ }, -/* 50 */ +/* 51 */ /***/ function(module, exports, __webpack_require__) { - var PhysicsMixin = __webpack_require__(51); - var ClusterMixin = __webpack_require__(55); - var SectorsMixin = __webpack_require__(56); - var SelectionMixin = __webpack_require__(57); - var ManipulationMixin = __webpack_require__(58); - var NavigationMixin = __webpack_require__(59); - var HierarchicalLayoutMixin = __webpack_require__(60); + var PhysicsMixin = __webpack_require__(52); + var ClusterMixin = __webpack_require__(56); + var SectorsMixin = __webpack_require__(57); + var SelectionMixin = __webpack_require__(58); + var ManipulationMixin = __webpack_require__(59); + var NavigationMixin = __webpack_require__(60); + var HierarchicalLayoutMixin = __webpack_require__(61); /** * Load a mixin into the network object @@ -25804,13 +26036,13 @@ return /******/ (function(modules) { // webpackBootstrap /***/ }, -/* 51 */ +/* 52 */ /***/ function(module, exports, __webpack_require__) { var util = __webpack_require__(1); - var RepulsionMixin = __webpack_require__(52); - var HierarchialRepulsionMixin = __webpack_require__(53); - var BarnesHutMixin = __webpack_require__(54); + var RepulsionMixin = __webpack_require__(53); + var HierarchialRepulsionMixin = __webpack_require__(54); + var BarnesHutMixin = __webpack_require__(55); /** * Toggling barnes Hut calculation on and off. @@ -26518,7 +26750,7 @@ return /******/ (function(modules) { // webpackBootstrap /***/ }, -/* 52 */ +/* 53 */ /***/ function(module, exports, __webpack_require__) { /** @@ -26582,7 +26814,7 @@ return /******/ (function(modules) { // webpackBootstrap /***/ }, -/* 53 */ +/* 54 */ /***/ function(module, exports, __webpack_require__) { /** @@ -26741,7 +26973,7 @@ return /******/ (function(modules) { // webpackBootstrap }; /***/ }, -/* 54 */ +/* 55 */ /***/ function(module, exports, __webpack_require__) { /** @@ -27146,7 +27378,7 @@ return /******/ (function(modules) { // webpackBootstrap /***/ }, -/* 55 */ +/* 56 */ /***/ function(module, exports, __webpack_require__) { /** @@ -28289,7 +28521,7 @@ return /******/ (function(modules) { // webpackBootstrap /***/ }, -/* 56 */ +/* 57 */ /***/ function(module, exports, __webpack_require__) { var util = __webpack_require__(1); @@ -28843,10 +29075,10 @@ return /******/ (function(modules) { // webpackBootstrap /***/ }, -/* 57 */ +/* 58 */ /***/ function(module, exports, __webpack_require__) { - var Node = __webpack_require__(47); + var Node = __webpack_require__(48); /** * This function can be called from the _doInAllSectors function @@ -29554,12 +29786,12 @@ return /******/ (function(modules) { // webpackBootstrap /***/ }, -/* 58 */ +/* 59 */ /***/ function(module, exports, __webpack_require__) { var util = __webpack_require__(1); - var Node = __webpack_require__(47); - var Edge = __webpack_require__(48); + var Node = __webpack_require__(48); + var Edge = __webpack_require__(49); /** * clears the toolbar div element of children @@ -29623,6 +29855,8 @@ return /******/ (function(modules) { // webpackBootstrap this.off('select', this.boundFunction); } + var locale = this.constants.locales[this.constants.locale]; + if (this.edgeBeingEdited !== undefined) { this.edgeBeingEdited._disableControlNodes(); this.edgeBeingEdited = undefined; @@ -29644,30 +29878,31 @@ return /******/ (function(modules) { // webpackBootstrap while (this.manipulationDiv.hasChildNodes()) { this.manipulationDiv.removeChild(this.manipulationDiv.firstChild); } + // add the icons to the manipulator div this.manipulationDiv.innerHTML = "" + "" + - ""+this.constants.labels['add'] +"" + + ""+locale['add'] +"" + "
" + "" + - ""+this.constants.labels['link'] +""; + ""+locale['link'] +""; if (this._getSelectedNodeCount() == 1 && this.triggerFunctions.edit) { this.manipulationDiv.innerHTML += "" + "
" + "" + - ""+this.constants.labels['editNode'] +""; + ""+locale['editNode'] +""; } else if (this._getSelectedEdgeCount() == 1 && this._getSelectedNodeCount() == 0) { this.manipulationDiv.innerHTML += "" + "
" + "" + - ""+this.constants.labels['editEdge'] +""; + ""+locale['editEdge'] +""; } if (this._selectionIsEmpty() == false) { this.manipulationDiv.innerHTML += "" + "
" + "" + - ""+this.constants.labels['del'] +""; + ""+locale['del'] +""; } @@ -29697,7 +29932,7 @@ return /******/ (function(modules) { // webpackBootstrap else { this.editModeDiv.innerHTML = "" + "" + - "" + this.constants.labels['edit'] + ""; + "" + locale['edit'] + ""; var editModeButton = document.getElementById("network-manipulate-editModeButton"); editModeButton.onclick = this._toggleEditMode.bind(this); } @@ -29717,13 +29952,15 @@ return /******/ (function(modules) { // webpackBootstrap this.off('select', this.boundFunction); } + var locale = this.constants.locales[this.constants.locale]; + // create the toolbar contents this.manipulationDiv.innerHTML = "" + "" + - "" + this.constants.labels['back'] + " " + + "" + locale['back'] + " " + "
" + "" + - "" + this.constants.labels['addDescription'] + ""; + "" + locale['addDescription'] + ""; // bind the icon var backButton = document.getElementById("network-manipulate-back"); @@ -29746,6 +29983,8 @@ return /******/ (function(modules) { // webpackBootstrap this._unselectAll(true); this.freezeSimulation = true; + var locale = this.constants.locales[this.constants.locale]; + if (this.boundFunction) { this.off('select', this.boundFunction); } @@ -29756,10 +29995,10 @@ return /******/ (function(modules) { // webpackBootstrap this.manipulationDiv.innerHTML = "" + "" + - "" + this.constants.labels['back'] + " " + + "" + locale['back'] + " " + "
" + "" + - "" + this.constants.labels['linkDescription'] + ""; + "" + locale['linkDescription'] + ""; // bind the icon var backButton = document.getElementById("network-manipulate-back"); @@ -29796,12 +30035,14 @@ return /******/ (function(modules) { // webpackBootstrap this.edgeBeingEdited = this._getSelectedEdge(); this.edgeBeingEdited._enableControlNodes(); + var locale = this.constants.locales[this.constants.locale]; + this.manipulationDiv.innerHTML = "" + "" + - "" + this.constants.labels['back'] + " " + + "" + locale['back'] + " " + "
" + "" + - "" + this.constants.labels['editEdgeDescription'] + ""; + "" + locale['editEdgeDescription'] + ""; // bind the icon var backButton = document.getElementById("network-manipulate-back"); @@ -29887,9 +30128,10 @@ return /******/ (function(modules) { // webpackBootstrap exports._handleConnect = function(pointer) { if (this._getSelectedNodeCount() == 0) { var node = this._getNodeAt(pointer); + if (node != null) { if (node.clusterSize > 1) { - alert("Cannot create edges to a cluster.") + alert(this.constants.locales[this.constants.locale]['createEdgeError']) } else { this._selectObject(node,false); @@ -29945,7 +30187,7 @@ return /******/ (function(modules) { // webpackBootstrap var node = this._getNodeAt(pointer); if (node != null) { if (node.clusterSize > 1) { - alert("Cannot create edges to a cluster.") + alert(this.constants.locales[this.constants.locale]["createEdgeError"]) } else { this._createEdge(connectFromId,node.id); @@ -29975,7 +30217,7 @@ return /******/ (function(modules) { // webpackBootstrap }); } else { - alert(this.constants.labels['addError']); + throw new Error('The function for add does not support two arguments (data,callback)'); this._createManipulatorBar(); this.moving = true; this.start(); @@ -30009,7 +30251,7 @@ return /******/ (function(modules) { // webpackBootstrap }); } else { - alert(this.constants.labels["linkError"]); + throw new Error('The function for connect does not support two arguments (data,callback)'); this.moving = true; this.start(); } @@ -30040,7 +30282,7 @@ return /******/ (function(modules) { // webpackBootstrap }); } else { - alert(this.constants.labels["linkError"]); + throw new Error('The function for edit does not support two arguments (data, callback)'); this.moving = true; this.start(); } @@ -30083,11 +30325,11 @@ return /******/ (function(modules) { // webpackBootstrap }); } else { - alert(this.constants.labels["editError"]); + throw new Error('The function for edit does not support two arguments (data, callback)'); } } else { - alert(this.constants.labels["editBoundError"]); + throw new Error('No edit function has been bound to this button'); } }; @@ -30117,7 +30359,7 @@ return /******/ (function(modules) { // webpackBootstrap }); } else { - alert(this.constants.labels["deleteError"]) + throw new Error('The function for delete does not support two arguments (data, callback)') } } else { @@ -30129,14 +30371,14 @@ return /******/ (function(modules) { // webpackBootstrap } } else { - alert(this.constants.labels["deleteClusterError"]); + alert(this.constants.locales[this.constants.locale]["deleteClusterError"]); } } }; /***/ }, -/* 59 */ +/* 60 */ /***/ function(module, exports, __webpack_require__) { var util = __webpack_require__(1); @@ -30291,7 +30533,7 @@ return /******/ (function(modules) { // webpackBootstrap /***/ }, -/* 60 */ +/* 61 */ /***/ function(module, exports, __webpack_require__) { exports._resetLevels = function() { @@ -30353,7 +30595,7 @@ return /******/ (function(modules) { // webpackBootstrap // if the user defined some levels but not all, alert and run without hierarchical layout if (undefinedLevel == true && definedLevel == true) { - alert("To use the hierarchical layout, nodes require either no predefined levels or levels have to be defined for all nodes."); + throw new Error("To use the hierarchical layout, nodes require either no predefined levels or levels have to be defined for all nodes."); this.zoomExtent(true,this.constants.clustering.enabled); if (!this.constants.clustering.enabled) { this.start(); @@ -30619,7 +30861,48 @@ return /******/ (function(modules) { // webpackBootstrap /***/ }, -/* 61 */ +/* 62 */ +/***/ function(module, exports, __webpack_require__) { + + // English + exports['en'] = { + add: 'Add Node', + edit: 'Edit', + link: 'Add Link', + del: 'Delete selected', + editNode: 'Edit Node', + editEdge: 'Edit Edge', + back: 'Back', + addDescription: 'Click in an empty space to place a new node.', + linkDescription: 'Click on a node and drag the edge to another node to connect them.', + editEdgeDescription: 'Click on the control points and drag them to a node to connect to it.', + createEdgeError: 'Cannot link edges to a cluster.', + deleteClusterError: 'Clusters cannot be deleted.' + }; + exports['en_EN'] = exports['en']; + exports['en_US'] = exports['en']; + + // Dutch + exports['nl'] = { + add: 'Node', + edit: 'Wijzigen', + link: 'Link toevoegen', + del: 'Selectie verwijderen', + editNode: 'Node wijzigen', + editEdge: 'Link wijzigen', + back: 'Terug', + addDescription: 'Klik op een leeg gebied om een nieuwe node te maken.', + linkDescription: 'Klik op een node en sleep de link naar een andere node om ze te verbinden.', + editEdgeDescription: 'Klik op de verbindingspunten en sleep ze naar een node om daarmee te verbinden.', + createEdgeError: 'Kan geen link maken naar een cluster.', + deleteClusterError: 'Clusters kunnen niet worden verwijderd.' + }; + exports['nl_NL'] = exports['nl']; + exports['nl_BE'] = exports['nl']; + + +/***/ }, +/* 63 */ /***/ function(module, exports, __webpack_require__) { /** @@ -30851,4 +31134,4 @@ return /******/ (function(modules) { // webpackBootstrap /***/ } /******/ ]) -}) +}); diff --git a/dist/vis.min.css b/dist/vis.min.css index e2d0bf66..54148cbe 100755 --- a/dist/vis.min.css +++ b/dist/vis.min.css @@ -1 +1 @@ -.vis.timeline.root{position:relative;border:1px solid #bfbfbf;overflow:hidden;padding:0;margin:0;box-sizing:border-box}.vis.timeline .vispanel{position:absolute;padding:0;margin:0;box-sizing:border-box}.vis.timeline .vispanel.bottom,.vis.timeline .vispanel.center,.vis.timeline .vispanel.left,.vis.timeline .vispanel.right,.vis.timeline .vispanel.top{border:1px #bfbfbf}.vis.timeline .vispanel.center,.vis.timeline .vispanel.left,.vis.timeline .vispanel.right{border-top-style:solid;border-bottom-style:solid;overflow:hidden}.vis.timeline .vispanel.bottom,.vis.timeline .vispanel.center,.vis.timeline .vispanel.top{border-left-style:solid;border-right-style:solid}.vis.timeline .background{overflow:hidden}.vis.timeline .vispanel>.content{position:relative}.vis.timeline .vispanel .shadow{position:absolute;width:100%;height:1px;box-shadow:0 0 10px rgba(0,0,0,.8)}.vis.timeline .vispanel .shadow.top{top:-1px;left:0}.vis.timeline .vispanel .shadow.bottom{bottom:-1px;left:0}.vis.timeline .labelset{position:relative;width:100%;overflow:hidden;box-sizing:border-box}.vis.timeline .labelset .vlabel{position:relative;left:0;top:0;width:100%;color:#4d4d4d;box-sizing:border-box;border-bottom:1px solid #bfbfbf}.vis.timeline .labelset .vlabel:last-child{border-bottom:none}.vis.timeline .labelset .vlabel .inner{display:inline-block;padding:5px}.vis.timeline .labelset .vlabel .inner.hidden{padding:0}.vis.timeline .itemset{position:relative;padding:0;margin:0;box-sizing:border-box}.vis.timeline .itemset .background,.vis.timeline .itemset .foreground{position:absolute;width:100%;height:100%}.vis.timeline .axis{position:absolute;width:100%;height:0;left:1px;z-index:1}.vis.timeline .foreground .group{position:relative;box-sizing:border-box;border-bottom:1px solid #bfbfbf}.vis.timeline .foreground .group:last-child{border-bottom:none}.vis.timeline .item{position:absolute;color:#1A1A1A;border-color:#97B0F8;border-width:1px;background-color:#D5DDF6;display:inline-block;padding:5px}.vis.timeline .item.selected{border-color:#FFC200;background-color:#FFF785;z-index:999}.vis.timeline .editable .item.selected{cursor:move}.vis.timeline .item.point.selected{background-color:#FFF785}.vis.timeline .item.box{text-align:center;border-style:solid;border-radius:2px}.vis.timeline .item.point{background:0 0}.vis.timeline .item.dot{position:absolute;padding:0;border-width:4px;border-style:solid;border-radius:4px}.vis.timeline .item.range{border-style:solid;border-radius:2px;box-sizing:border-box}.vis.timeline .item.range .content{position:relative;display:inline-block;overflow:hidden;max-width:100%}.vis.timeline .item.line{padding:0;position:absolute;width:0;border-left-width:1px;border-left-style:solid}.vis.timeline .item .content{white-space:nowrap;overflow:hidden}.vis.timeline .item .delete{background:url(img/timeline/delete.png) no-repeat top center;position:absolute;width:24px;height:24px;top:0;right:-24px;cursor:pointer}.vis.timeline .item.range .drag-left{position:absolute;width:24px;height:100%;top:0;left:-4px;cursor:w-resize;z-index:10000}.vis.timeline .item.range .drag-right{position:absolute;width:24px;height:100%;top:0;right:-4px;cursor:e-resize;z-index:10001}.vis.timeline .timeaxis{position:relative;overflow:hidden}.vis.timeline .timeaxis.foreground{top:0;left:0;width:100%}.vis.timeline .timeaxis.background{position:absolute;top:0;left:0;width:100%;height:100%}.vis.timeline .timeaxis .text{position:absolute;color:#4d4d4d;padding:3px;white-space:nowrap}.vis.timeline .timeaxis .text.measure{position:absolute;padding-left:0;padding-right:0;margin-left:0;margin-right:0;visibility:hidden}.vis.timeline .timeaxis .grid.vertical{position:absolute;width:0;border-right:1px solid}.vis.timeline .timeaxis .grid.minor{border-color:#e5e5e5}.vis.timeline .timeaxis .grid.major{border-color:#bfbfbf}.vis.timeline .currenttime{background-color:#FF7F6E;width:2px;z-index:1}.vis.timeline .customtime{background-color:#6E94FF;width:2px;cursor:move;z-index:1}.vis.timeline .vispanel.background.horizontal .grid.horizontal{position:absolute;width:100%;height:0;border-bottom:1px solid}.vis.timeline .vispanel.background.horizontal .grid.minor{border-color:#e5e5e5}.vis.timeline .vispanel.background.horizontal .grid.major{border-color:#bfbfbf}.vis.timeline .dataaxis .yAxis.major{width:100%;position:absolute;color:#4d4d4d;white-space:nowrap}.vis.timeline .dataaxis .yAxis.major.measure{padding:0;margin:0;visibility:hidden;width:auto}.vis.timeline .dataaxis .yAxis.minor{position:absolute;width:100%;color:#bebebe;white-space:nowrap}.vis.timeline .dataaxis .yAxis.minor.measure{padding:0;margin:0;visibility:hidden;width:auto}.vis.timeline .legend{background-color:rgba(247,252,255,.65);padding:5px;border-color:#b3b3b3;border-style:solid;border-width:1px;box-shadow:2px 2px 10px rgba(154,154,154,.55)}.vis.timeline .legendText{white-space:nowrap;display:inline-block}.vis.timeline .graphGroup0{fill:#4f81bd;fill-opacity:0;stroke-width:2px;stroke:#4f81bd}.vis.timeline .graphGroup1{fill:#f79646;fill-opacity:0;stroke-width:2px;stroke:#f79646}.vis.timeline .graphGroup2{fill:#8c51cf;fill-opacity:0;stroke-width:2px;stroke:#8c51cf}.vis.timeline .graphGroup3{fill:#75c841;fill-opacity:0;stroke-width:2px;stroke:#75c841}.vis.timeline .graphGroup4{fill:#ff0100;fill-opacity:0;stroke-width:2px;stroke:#ff0100}.vis.timeline .graphGroup5{fill:#37d8e6;fill-opacity:0;stroke-width:2px;stroke:#37d8e6}.vis.timeline .graphGroup6{fill:#042662;fill-opacity:0;stroke-width:2px;stroke:#042662}.vis.timeline .graphGroup7{fill:#00ff26;fill-opacity:0;stroke-width:2px;stroke:#00ff26}.vis.timeline .graphGroup8{fill:#f0f;fill-opacity:0;stroke-width:2px;stroke:#f0f}.vis.timeline .graphGroup9{fill:#8f3938;fill-opacity:0;stroke-width:2px;stroke:#8f3938}.vis.timeline .fill{fill-opacity:.1;stroke:none}.vis.timeline .bar{fill-opacity:.5;stroke-width:1px}.vis.timeline .point{stroke-width:2px;fill-opacity:1}.vis.timeline .legendBackground{stroke-width:1px;fill-opacity:.9;fill:#fff;stroke:#c2c2c2}.vis.timeline .outline{stroke-width:1px;fill-opacity:1;fill:#fff;stroke:#e5e5e5}.vis.timeline .iconFill{fill-opacity:.3;stroke:none}div.network-manipulationDiv{border-width:0;border-bottom:1px;border-style:solid;border-color:#d6d9d8;background:#fff;background:-moz-linear-gradient(top,#fff 0,#fcfcfc 48%,#fafafa 50%,#fcfcfc 100%);background:-webkit-gradient(linear,left top,left bottom,color-stop(0%,#fff),color-stop(48%,#fcfcfc),color-stop(50%,#fafafa),color-stop(100%,#fcfcfc));background:-webkit-linear-gradient(top,#fff 0,#fcfcfc 48%,#fafafa 50%,#fcfcfc 100%);background:-o-linear-gradient(top,#fff 0,#fcfcfc 48%,#fafafa 50%,#fcfcfc 100%);background:-ms-linear-gradient(top,#fff 0,#fcfcfc 48%,#fafafa 50%,#fcfcfc 100%);background:linear-gradient(to bottom,#fff 0,#fcfcfc 48%,#fafafa 50%,#fcfcfc 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#fcfcfc', GradientType=0);width:600px;height:30px;z-index:10;position:absolute}div.network-manipulation-editMode{height:30px;z-index:10;position:absolute;margin-top:20px}div.network-manipulation-closeDiv{height:30px;width:30px;z-index:11;position:absolute;margin-top:3px;margin-left:590px;background-position:0 0;background-repeat:no-repeat;background-image:url(img/network/cross.png);cursor:pointer;-webkit-touch-callout:none;-webkit-user-select:none;-khtml-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}span.network-manipulationUI{font-family:verdana;font-size:12px;-moz-border-radius:15px;border-radius:15px;display:inline-block;background-position:0 0;background-repeat:no-repeat;height:24px;margin:-14px 0 0 10px;vertical-align:middle;cursor:pointer;padding:0 8px;-webkit-touch-callout:none;-webkit-user-select:none;-khtml-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}span.network-manipulationUI:hover{box-shadow:1px 1px 8px rgba(0,0,0,.2)}span.network-manipulationUI:active{box-shadow:1px 1px 8px rgba(0,0,0,.5)}span.network-manipulationUI.back{background-image:url(img/network/backIcon.png)}span.network-manipulationUI.none:hover{box-shadow:1px 1px 8px transparent;cursor:default}span.network-manipulationUI.none:active{box-shadow:1px 1px 8px transparent}span.network-manipulationUI.none{padding:0}span.network-manipulationUI.notification{margin:2px;font-weight:700}span.network-manipulationUI.add{background-image:url(img/network/addNodeIcon.png)}span.network-manipulationUI.edit{background-image:url(img/network/editIcon.png)}span.network-manipulationUI.edit.editmode{background-color:#fcfcfc;border-style:solid;border-width:1px;border-color:#ccc}span.network-manipulationUI.connect{background-image:url(img/network/connectIcon.png)}span.network-manipulationUI.delete{background-image:url(img/network/deleteIcon.png)}span.network-manipulationLabel{margin:0 0 0 23px;line-height:25px}div.network-seperatorLine{display:inline-block;width:1px;height:20px;background-color:#bdbdbd;margin:5px 7px 0 15px}div.network-navigation{width:34px;height:34px;z-index:10;-moz-border-radius:17px;border-radius:17px;position:absolute;display:inline-block;background-position:2px 2px;background-repeat:no-repeat;cursor:pointer;-webkit-touch-callout:none;-webkit-user-select:none;-khtml-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}div.network-navigation:hover{box-shadow:0 0 3px 3px rgba(56,207,21,.3)}div.network-navigation:active{box-shadow:0 0 1px 3px rgba(56,207,21,.95)}div.network-navigation.up{background-image:url(img/network/upArrow.png);bottom:50px;left:55px}div.network-navigation.down{background-image:url(img/network/downArrow.png);bottom:10px;left:55px}div.network-navigation.left{background-image:url(img/network/leftArrow.png);bottom:10px;left:15px}div.network-navigation.right{background-image:url(img/network/rightArrow.png);bottom:10px;left:95px}div.network-navigation.zoomIn{background-image:url(img/network/plus.png);bottom:10px;right:15px}div.network-navigation.zoomOut{background-image:url(img/network/minus.png);bottom:10px;right:55px}div.network-navigation.zoomExtends{background-image:url(img/network/zoomExtends.png);bottom:50px;right:15px} \ No newline at end of file +.vis.timeline.root{position:relative;border:1px solid #bfbfbf;overflow:hidden;padding:0;margin:0;box-sizing:border-box}.vis.timeline .vispanel{position:absolute;padding:0;margin:0;box-sizing:border-box}.vis.timeline .vispanel.bottom,.vis.timeline .vispanel.center,.vis.timeline .vispanel.left,.vis.timeline .vispanel.right,.vis.timeline .vispanel.top{border:1px #bfbfbf}.vis.timeline .vispanel.center,.vis.timeline .vispanel.left,.vis.timeline .vispanel.right{border-top-style:solid;border-bottom-style:solid;overflow:hidden}.vis.timeline .vispanel.bottom,.vis.timeline .vispanel.center,.vis.timeline .vispanel.top{border-left-style:solid;border-right-style:solid}.vis.timeline .background{overflow:hidden}.vis.timeline .vispanel>.content{position:relative}.vis.timeline .vispanel .shadow{position:absolute;width:100%;height:1px;box-shadow:0 0 10px rgba(0,0,0,.8)}.vis.timeline .vispanel .shadow.top{top:-1px;left:0}.vis.timeline .vispanel .shadow.bottom{bottom:-1px;left:0}.vis.timeline .labelset{position:relative;width:100%;overflow:hidden;box-sizing:border-box}.vis.timeline .labelset .vlabel{position:relative;left:0;top:0;width:100%;color:#4d4d4d;box-sizing:border-box;border-bottom:1px solid #bfbfbf}.vis.timeline .labelset .vlabel:last-child{border-bottom:none}.vis.timeline .labelset .vlabel .inner{display:inline-block;padding:5px}.vis.timeline .labelset .vlabel .inner.hidden{padding:0}.vis.timeline .itemset{position:relative;padding:0;margin:0;box-sizing:border-box}.vis.timeline .itemset .background,.vis.timeline .itemset .foreground{position:absolute;width:100%;height:100%}.vis.timeline .axis{position:absolute;width:100%;height:0;left:1px;z-index:1}.vis.timeline .foreground .group{position:relative;box-sizing:border-box;border-bottom:1px solid #bfbfbf}.vis.timeline .foreground .group:last-child{border-bottom:none}.vis.timeline .item{position:absolute;color:#1A1A1A;border-color:#97B0F8;border-width:1px;background-color:#D5DDF6;display:inline-block;padding:5px}.vis.timeline .item.selected{border-color:#FFC200;background-color:#FFF785;z-index:999}.vis.timeline .editable .item.selected{cursor:move}.vis.timeline .item.point.selected{background-color:#FFF785}.vis.timeline .item.box{text-align:center;border-style:solid;border-radius:2px}.vis.timeline .item.point{background:0 0}.vis.timeline .item.dot{position:absolute;padding:0;border-width:4px;border-style:solid;border-radius:4px}.vis.timeline .item.range{border-style:solid;border-radius:2px;box-sizing:border-box}.vis.timeline .item.range .content{position:relative;display:inline-block;overflow:hidden;max-width:100%}.vis.timeline .item.line{padding:0;position:absolute;width:0;border-left-width:1px;border-left-style:solid}.vis.timeline .item .content{white-space:nowrap;overflow:hidden}.vis.timeline .item .delete{background:url(img/timeline/delete.png) top center no-repeat;position:absolute;width:24px;height:24px;top:0;right:-24px;cursor:pointer}.vis.timeline .item.range .drag-left{position:absolute;width:24px;height:100%;top:0;left:-4px;cursor:w-resize;z-index:10000}.vis.timeline .item.range .drag-right{position:absolute;width:24px;height:100%;top:0;right:-4px;cursor:e-resize;z-index:10001}.vis.timeline .timeaxis{position:relative;overflow:hidden}.vis.timeline .timeaxis.foreground{top:0;left:0;width:100%}.vis.timeline .timeaxis.background{position:absolute;top:0;left:0;width:100%;height:100%}.vis.timeline .timeaxis .text{position:absolute;color:#4d4d4d;padding:3px;white-space:nowrap}.vis.timeline .timeaxis .text.measure{position:absolute;padding-left:0;padding-right:0;margin-left:0;margin-right:0;visibility:hidden}.vis.timeline .timeaxis .grid.vertical{position:absolute;width:0;border-right:1px solid}.vis.timeline .timeaxis .grid.minor{border-color:#e5e5e5}.vis.timeline .timeaxis .grid.major{border-color:#bfbfbf}.vis.timeline .currenttime{background-color:#FF7F6E;width:2px;z-index:1}.vis.timeline .customtime{background-color:#6E94FF;width:2px;cursor:move;z-index:1}.vis.timeline .vispanel.background.horizontal .grid.horizontal{position:absolute;width:100%;height:0;border-bottom:1px solid}.vis.timeline .vispanel.background.horizontal .grid.minor{border-color:#e5e5e5}.vis.timeline .vispanel.background.horizontal .grid.major{border-color:#bfbfbf}.vis.timeline .dataaxis .yAxis.major{width:100%;position:absolute;color:#4d4d4d;white-space:nowrap}.vis.timeline .dataaxis .yAxis.major.measure{padding:0;margin:0;visibility:hidden;width:auto}.vis.timeline .dataaxis .yAxis.minor{position:absolute;width:100%;color:#bebebe;white-space:nowrap}.vis.timeline .dataaxis .yAxis.minor.measure{padding:0;margin:0;visibility:hidden;width:auto}.vis.timeline .legend{background-color:rgba(247,252,255,.65);padding:5px;border-color:#b3b3b3;border-style:solid;border-width:1px;box-shadow:2px 2px 10px rgba(154,154,154,.55)}.vis.timeline .legendText{white-space:nowrap;display:inline-block}.vis.timeline .graphGroup0{fill:#4f81bd;fill-opacity:0;stroke-width:2px;stroke:#4f81bd}.vis.timeline .graphGroup1{fill:#f79646;fill-opacity:0;stroke-width:2px;stroke:#f79646}.vis.timeline .graphGroup2{fill:#8c51cf;fill-opacity:0;stroke-width:2px;stroke:#8c51cf}.vis.timeline .graphGroup3{fill:#75c841;fill-opacity:0;stroke-width:2px;stroke:#75c841}.vis.timeline .graphGroup4{fill:#ff0100;fill-opacity:0;stroke-width:2px;stroke:#ff0100}.vis.timeline .graphGroup5{fill:#37d8e6;fill-opacity:0;stroke-width:2px;stroke:#37d8e6}.vis.timeline .graphGroup6{fill:#042662;fill-opacity:0;stroke-width:2px;stroke:#042662}.vis.timeline .graphGroup7{fill:#00ff26;fill-opacity:0;stroke-width:2px;stroke:#00ff26}.vis.timeline .graphGroup8{fill:#f0f;fill-opacity:0;stroke-width:2px;stroke:#f0f}.vis.timeline .graphGroup9{fill:#8f3938;fill-opacity:0;stroke-width:2px;stroke:#8f3938}.vis.timeline .fill{fill-opacity:.1;stroke:none}.vis.timeline .bar{fill-opacity:.5;stroke-width:1px}.vis.timeline .point{stroke-width:2px;fill-opacity:1}.vis.timeline .legendBackground{stroke-width:1px;fill-opacity:.9;fill:#fff;stroke:#c2c2c2}.vis.timeline .outline{stroke-width:1px;fill-opacity:1;fill:#fff;stroke:#e5e5e5}.vis.timeline .iconFill{fill-opacity:.3;stroke:none}div.network-manipulationDiv{border-width:0;border-bottom:1px;border-style:solid;border-color:#d6d9d8;background:#fff;background:-moz-linear-gradient(top,#fff 0,#fcfcfc 48%,#fafafa 50%,#fcfcfc 100%);background:-webkit-gradient(linear,left top,left bottom,color-stop(0%,#fff),color-stop(48%,#fcfcfc),color-stop(50%,#fafafa),color-stop(100%,#fcfcfc));background:-webkit-linear-gradient(top,#fff 0,#fcfcfc 48%,#fafafa 50%,#fcfcfc 100%);background:-o-linear-gradient(top,#fff 0,#fcfcfc 48%,#fafafa 50%,#fcfcfc 100%);background:-ms-linear-gradient(top,#fff 0,#fcfcfc 48%,#fafafa 50%,#fcfcfc 100%);background:linear-gradient(to bottom,#fff 0,#fcfcfc 48%,#fafafa 50%,#fcfcfc 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#fcfcfc', GradientType=0);width:600px;height:30px;z-index:10;position:absolute}div.network-manipulation-editMode{height:30px;z-index:10;position:absolute;margin-top:20px}div.network-manipulation-closeDiv{height:30px;width:30px;z-index:11;position:absolute;margin-top:3px;margin-left:590px;background-position:0 0;background-repeat:no-repeat;background-image:url(img/network/cross.png);cursor:pointer;-webkit-touch-callout:none;-webkit-user-select:none;-khtml-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}span.network-manipulationUI{font-family:verdana;font-size:12px;-moz-border-radius:15px;border-radius:15px;display:inline-block;background-position:0 0;background-repeat:no-repeat;height:24px;margin:-14px 0 0 10px;vertical-align:middle;cursor:pointer;padding:0 8px;-webkit-touch-callout:none;-webkit-user-select:none;-khtml-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}span.network-manipulationUI:hover{box-shadow:1px 1px 8px rgba(0,0,0,.2)}span.network-manipulationUI:active{box-shadow:1px 1px 8px rgba(0,0,0,.5)}span.network-manipulationUI.back{background-image:url(img/network/backIcon.png)}span.network-manipulationUI.none:hover{box-shadow:1px 1px 8px transparent;cursor:default}span.network-manipulationUI.none:active{box-shadow:1px 1px 8px transparent}span.network-manipulationUI.none{padding:0}span.network-manipulationUI.notification{margin:2px;font-weight:700}span.network-manipulationUI.add{background-image:url(img/network/addNodeIcon.png)}span.network-manipulationUI.edit{background-image:url(img/network/editIcon.png)}span.network-manipulationUI.edit.editmode{background-color:#fcfcfc;border-style:solid;border-width:1px;border-color:#ccc}span.network-manipulationUI.connect{background-image:url(img/network/connectIcon.png)}span.network-manipulationUI.delete{background-image:url(img/network/deleteIcon.png)}span.network-manipulationLabel{margin:0 0 0 23px;line-height:25px}div.network-seperatorLine{display:inline-block;width:1px;height:20px;background-color:#bdbdbd;margin:5px 7px 0 15px}div.network-navigation{width:34px;height:34px;z-index:10;-moz-border-radius:17px;border-radius:17px;position:absolute;display:inline-block;background-position:2px 2px;background-repeat:no-repeat;cursor:pointer;-webkit-touch-callout:none;-webkit-user-select:none;-khtml-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}div.network-navigation:hover{box-shadow:0 0 3px 3px rgba(56,207,21,.3)}div.network-navigation:active{box-shadow:0 0 1px 3px rgba(56,207,21,.95)}div.network-navigation.up{background-image:url(img/network/upArrow.png);bottom:50px;left:55px}div.network-navigation.down{background-image:url(img/network/downArrow.png);bottom:10px;left:55px}div.network-navigation.left{background-image:url(img/network/leftArrow.png);bottom:10px;left:15px}div.network-navigation.right{background-image:url(img/network/rightArrow.png);bottom:10px;left:95px}div.network-navigation.zoomIn{background-image:url(img/network/plus.png);bottom:10px;right:15px}div.network-navigation.zoomOut{background-image:url(img/network/minus.png);bottom:10px;right:55px}div.network-navigation.zoomExtends{background-image:url(img/network/zoomExtends.png);bottom:50px;right:15px} \ No newline at end of file diff --git a/docs/network.html b/docs/network.html index 43e3d9fa..b9db47cf 100644 --- a/docs/network.html +++ b/docs/network.html @@ -31,9 +31,9 @@

- Every dataset is different. Nodes can have different sizes based on content, interconnectivity can be high or low etc. Because of this, network has a special option - that the user can use to explore which settings may be good for you. Use configurePhysics as described in the Physics section or by - example 25. + Every dataset is different. Nodes can have different sizes based on content, interconnectivity can be high or low etc. Because of this, network has a special option + that the user can use to explore which settings may be good for you. Use configurePhysics as described in the Physics section or by + example 25.

@@ -68,8 +68,8 @@

  • Clustering
  • Navigation controls
  • Keyboard navigation
  • -
  • Hierarchical layout
  • -
  • Localization
  • +
  • Hierarchical layout
  • +
  • Localization
  • Tooltips
  • @@ -256,246 +256,246 @@ When using a DataSet, the network is automatically updating to changes in the Da

    - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + - - - - - - + + + + + + - - - - - - - - - - - - + + + + + + - - - - - - + + + + + + - - - - - - + + + + + + - - - - - - + + + + + + - - - - - - + + + + + + - - - - - - + + + + + + - - - - - - - - - - - - - - - - - - + + + + + + - - - - - - + + + + + + - - - - - - + + + + + + - - - - - - + + + + + + - - - - - + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - + + + + + + - - - - - + + + + + - In case of image, a property with name image must - be provided, containing image urls. -

    + + + + + + - The shapes dot, star, triangle, - triangleDown, and square, are scalable. - The size is determined by the properties radius or - value. -

    + + + + + + + + + + + + + + + + + + - When a property label is provided, - this label will be displayed inside the shape in case of shapes - box, circle, ellipse, - and database. - For all other shapes, the label will be displayed right below the shape. + + + + + + - - + + + + + + - - - - - - + + + + + + - - - - - - + + + + + + - - - - - - + + + + + + - - - - - - - - - - - - + + + + + + + + + + + +
    NameTypeRequiredDescription
    borderWidthNumber1The width of the border of the node when it is not selected, automatically limited by the width of the node.
    borderWidthSelectedNumberundefinedThe width of the border of the node when it is selected. If left at undefined, double the borderWidth will be used.
    colorString | ObjectnoColor for the node.
    NameTypeRequiredDescription
    color.backgroundStringnoBackground color for the node.
    borderWidthNumber1The width of the border of the node when it is not selected, automatically limited by the width of the node.
    color.borderStringnoBorder color for the node.
    color.highlightString | ObjectnoColor of the node when selected.
    borderWidthSelectedNumberundefinedThe width of the border of the node when it is selected. If left at undefined, double the borderWidth will be used.
    color.highlight.backgroundStringnoBackground color of the node when selected.
    colorString | ObjectnoColor for the node.
    color.highlight.borderStringnoBorder color of the node when selected.
    color.backgroundStringnoBackground color for the node.
    color.hover.backgroundStringnoBackground color of the node when the node is hovered over and the hover option is enabled.
    color.borderStringnoBorder color for the node.
    color.hover.borderStringnoBorder color of the node when the node is hovered over and the hover option is enabled.
    color.highlightString | ObjectnoColor of the node when selected.
    groupNumber | StringnoA group number or name. The type can be number, - string, or an other type. All nodes with the same group get - the same color schema.
    color.highlight.backgroundStringnoBackground color of the node when selected.
    allowedToMoveXBooleanfalseIf allowedToMoveX is false, then the node will not move from its supplied position. - If an X position has been supplied, it is fixed in the X-direction. - If no X value has been supplied, this argument will not do anything.
    allowedToMoveYBooleanfalseIf allowedToMoveY is false, then the node will not move from its supplied position. - If an Y position has been supplied, it is fixed in the Y-direction. - If no Y value has been supplied, this argument will not do anything.
    fontColorStringnoFont color for label in the node.
    color.highlight.borderStringnoBorder color of the node when selected.
    fontFaceStringnoFont face for label in the node, for example "verdana" or "arial".
    color.hover.backgroundStringnoBackground color of the node when the node is hovered over and the hover option is enabled.
    fontSizeNumbernoFont size in pixels for label in the node.
    color.hover.borderStringnoBorder color of the node when the node is hovered over and the hover option is enabled.
    idNumber | StringyesA unique id for this node. - Nodes may not have duplicate id's. - Id's do not need to be consecutive. - An id is normally a number, but may be any type.
    groupNumber | StringnoA group number or name. The type can be number, + string, or an other type. All nodes with the same group get + the same color schema.
    imagestringnoUrl of an image. Only applicable when the shape of the node is - image.
    allowedToMoveXBooleanfalseIf allowedToMoveX is false, then the node will not move from its supplied position. + If an X position has been supplied, it is fixed in the X-direction. + If no X value has been supplied, this argument will not do anything.
    allowedToMoveYBooleanfalseIf allowedToMoveY is false, then the node will not move from its supplied position. + If an Y position has been supplied, it is fixed in the Y-direction. + If no Y value has been supplied, this argument will not do anything.
    fontColorStringnoFont color for label in the node.
    massnumber1When using the Barnes Hut simulation method (which is selected by default), - the mass of a node determines the gravitational repulsion during the simulation. Higher mass will push other nodes further away.
    levelnumber-1This level is used in the hierarchical layout. If this is not selected, the level does not do anything.
    radiusnumbernoRadius for the node. Applicable for all shapes except box, - circle, ellipse and database. - The value of radius will override a value in - property value.
    fontFaceStringnoFont face for label in the node, for example "verdana" or "arial".
    shapestringnoDefine the shape for the node. - Choose from - ellipse (default), circle, box, - database, image, label, dot, - star, triangle, triangleDown, and square. -

    +
    fontSizeNumbernoFont size in pixels for label in the node.
    idNumber | StringyesA unique id for this node. + Nodes may not have duplicate id's. + Id's do not need to be consecutive. + An id is normally a number, but may be any type.
    imagestringnoUrl of an image. Only applicable when the shape of the node is + image.
    massnumber1When using the Barnes Hut simulation method (which is selected by default), + the mass of a node determines the gravitational repulsion during the simulation. Higher mass will push other nodes further away.
    levelnumber-1This level is used in the hierarchical layout. If this is not selected, the level does not do anything.
    radiusnumbernoRadius for the node. Applicable for all shapes except box, + circle, ellipse and database. + The value of radius will override a value in + property value.
    shapestringnoDefine the shape for the node. + Choose from + ellipse (default), circle, box, + database, image, label, dot, + star, triangle, triangleDown, and square. +

    + + In case of image, a property with name image must + be provided, containing image urls. +

    + + The shapes dot, star, triangle, + triangleDown, and square, are scalable. + The size is determined by the properties radius or + value. +

    + + When a property label is provided, + this label will be displayed inside the shape in case of shapes + box, circle, ellipse, + and database. + For all other shapes, the label will be displayed right below the shape. + +
    labelstringnoText label to be displayed in the node or under the image of the node. - Multiple lines can be separated by a newline character \n .
    labelstringnoText label to be displayed in the node or under the image of the node. + Multiple lines can be separated by a newline character \n .
    titlestring | functionnoTitle to be displayed when the user hovers over the node. - The title can contain HTML code. If using a function, returning undefined - will prevent the tooltip from being displayed.
    titlestring | functionnoTitle to be displayed when the user hovers over the node. + The title can contain HTML code. If using a function, returning undefined + will prevent the tooltip from being displayed.
    valuenumbernoA value for the node. - The radius of the nodes will be scaled automatically from minimum to - maximum value. - Only applicable when the shape of the node is dot. - If a radius is provided for the node too, it will override the - radius calculated from the value.
    valuenumbernoA value for the node. + The radius of the nodes will be scaled automatically from minimum to + maximum value. + Only applicable when the shape of the node is dot. + If a radius is provided for the node too, it will override the + radius calculated from the value.
    xnumbernoHorizontal position in pixels. - The horizontal position of the node will be fixed. - The vertical position y may remain undefined.
    ynumbernoVertical position in pixels. - The vertical position of the node will be fixed. - The horizontal position x may remain undefined.
    xnumbernoHorizontal position in pixels. + The horizontal position of the node will be fixed. + The vertical position y may remain undefined.
    ynumbernoVertical position in pixels. + The vertical position of the node will be fixed. + The horizontal position x may remain undefined.
    @@ -682,20 +682,20 @@ When using a DataSet, the network is automatically updating to changes in the Da no Text label to be displayed halfway the edge. - - length - number - physics.[method].springLength - The resting length of the edge when modeled as a spring. By default the springLength determined by the physics is used. By using this setting you can make certain edges have different resting lengths. - - - - inheritColor - String | Boolean - false - Possible values: "to","from", true, false. If this value is set to false, the edge color information is used. If the value is set to true or "from", - the color data from the borders of the "from" node is used. If this value is "to", the color data from the borders of the "to" node is used. - + + length + number + physics.[method].springLength + The resting length of the edge when modeled as a spring. By default the springLength determined by the physics is used. By using this setting you can make certain edges have different resting lengths. + + + + inheritColor + String | Boolean + false + Possible values: "to","from", true, false. If this value is set to false, the edge color information is used. If the value is set to true or "from", + the color data from the borders of the "from" node is used. If this value is "to", the color data from the borders of the "to" node is used. + title string | function @@ -763,13 +763,13 @@ var network = new vis.Network(container, data);

    Gephi import (JSON)

    - network can import data straight from an exported json file from gephi. You can get the JSON exporter here: - https://marketplace.gephi.org/plugin/json-exporter/. - An example exists showing how to get a JSON file into Vis: 30_importing_from_gephi. + network can import data straight from an exported json file from gephi. You can get the JSON exporter here: + https://marketplace.gephi.org/plugin/json-exporter/. + An example exists showing how to get a JSON file into Vis: 30_importing_from_gephi.

    - Example usage: + Example usage:

    @@ -815,29 +815,29 @@ var parserOptions = {
     var parsed = vis.network.gephiParser.parseGephi(gephiJSON, parserOptions);
     
    - + - + - + - - + + - +
    Name Type Default Description
    allowedToMove Boolean false - If true, the nodes will move according to the physics model after import. If false, the nodes do not move at all. + If true, the nodes will move according to the physics model after import. If false, the nodes do not move at all.
    parseColor Boolean false - If true, the color will be parsed by the vis parser, generating extra colors for the borders, highlighs and hover. If false, the node will be the supplied color. + If true, the color will be parsed by the vis parser, generating extra colors for the borders, highlighs and hover. If false, the node will be the supplied color.

    Configuration options

    @@ -863,218 +863,218 @@ var options = {

    - - - - - - + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + - - - - - - + + + + + + - - - - - - + + + + + + - - - - - - + + + + + + - - - - - - + + + + + + - - - - - - + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + - - - - - - + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - + + + + + + - - - - + + + + - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    NameTypeDefaultDescription
    NameTypeDefaultDescription
    physicsObjectnone - Configuration of the physics system governing the simulation of the nodes and edges. - Barnes-Hut nBody simulation is used by default. See section Physics for an overview of the available options. -
    configurePhysicsBooleanfalse - Enabling this setting will create a physics configuration div above the network. You can use this to fine tune the physics system to suit your needs. - Because of the many possible configurations, there is not a one-size-fits-all setting. By using this tool, you can adapt the physics to your dataset. -
    dataManipulationObjectnone - Settings for manipulating the Dataset. See section Data manipulation for an overview of the available options. -
    clusteringObjectnone - Clustering configuration. Clustering is turned off by default. See section Clustering for an overview of the available options. -
    physicsObjectnone + Configuration of the physics system governing the simulation of the nodes and edges. + Barnes-Hut nBody simulation is used by default. See section Physics for an overview of the available options. +
    configurePhysicsBooleanfalse + Enabling this setting will create a physics configuration div above the network. You can use this to fine tune the physics system to suit your needs. + Because of the many possible configurations, there is not a one-size-fits-all setting. By using this tool, you can adapt the physics to your dataset. +
    edgesObjectnone - Configuration options applied to all edges. See section Edges configuration for an overview of the available options. -
    dataManipulationObjectnone + Settings for manipulating the Dataset. See section Data manipulation for an overview of the available options. +
    freezeForStabilizationBooleanfalse - With the advent of the storePosition() function, the positions of the nodes can be saved after they are stabilized. The smoothCurves require support nodes and those positions are not stored. In order - to speed up the initialization of the network by using storePosition() and loading the nodes with the stored positions, the freezeForStabilization option freezes all nodes that have been supplied with - an x and y position in place during the stabilization. That way only the support nodes for the smooth curves have to stabilize, greatly speeding up the stabilization process with cached positions. -
    clusteringObjectnone + Clustering configuration. Clustering is turned off by default. See section Clustering for an overview of the available options. +
    groupsObjectnoneIt is possible to specify custom styles for groups. - Each node assigned a group gets the specified style. - See Groups configuration for an overview of the available styles - and an example. -
    edgesObjectnone + Configuration options applied to all edges. See section Edges configuration for an overview of the available options. +
    heightString"400px"The height of the network in pixels or as a percentage.
    freezeForStabilizationBooleanfalse + With the advent of the storePosition() function, the positions of the nodes can be saved after they are stabilized. The smoothCurves require support nodes and those positions are not stored. In order + to speed up the initialization of the network by using storePosition() and loading the nodes with the stored positions, the freezeForStabilization option freezes all nodes that have been supplied with + an x and y position in place during the stabilization. That way only the support nodes for the smooth curves have to stabilize, greatly speeding up the stabilization process with cached positions. +
    hoverBooleanfalseEnabling the change of the colors of nodes and edges when the mouse hovers over them. Enabling this may have a minor impact on performance.
    groupsObjectnoneIt is possible to specify custom styles for groups. + Each node assigned a group gets the specified style. + See Groups configuration for an overview of the available styles + and an example. +
    keyboardObjectnone - Configuration options for shortcuts keys. Shortcut keys are turned off by default. See section Keyboard navigation for an overview of the available options. -
    dragNetworkBooleantrue - Toggle if the network can be dragged. This will not affect the dragging of nodes. -
    dragNodesBooleantrue - Toggle if the nodes can be dragged. This will not affect the dragging of the network. -
    hideNodesOnDragBooleanfalse - Toggle if the nodes are drawn during a drag. This can greatly improve performance if you have many nodes. -
    hideEdgesOnDragBooleanfalse - Toggle if the edges are drawn during a drag. This can greatly improve performance if you have many edges. -
    navigationObjectnone - Configuration options for the navigation controls. See section Navigation controls for an overview of the available options. -
    heightString"400px"The height of the network in pixels or as a percentage.
    nodesObjectnone - Configuration options applied to all nodes. See section Nodes configuration for an overview of the available options. -
    hoverBooleanfalseEnabling the change of the colors of nodes and edges when the mouse hovers over them. Enabling this may have a minor impact on performance.
    smoothCurvesBoolean || objectobjectIf true, edges are drawn as smooth curves. This is more computationally intensive since the edge now is a quadratic Bezier curve. This can be further configured by the options below.
    smoothCurves.dynamicBooleantrueBy default, the edges are dynamic. This means there are support nodes placed in the middle of the edge. This support node is also handed by the physics simulation. If false, the smoothness will be based on the - relative positions of the to and from nodes. This is computationally cheaper but there is no self organisation.
    smoothCurves.typeString"continuous"This option only affects NONdynamic smooth curves. The supported types are: continuous, discrete, diagonalCross, straightCross, horizontal, vertical. The effects of these types - are shown in examples 26 and 27
    smoothCurves.roundnessNumber0.5This only affects NONdynamic smooth curves. The roundness can be tweaked with the parameter. The value range is from 0 to 1 with a maximum roundness at 0.5.
    selectableBooleantrueIf true, nodes in the network can be selected by clicking them. - Long press can be used to select multiple nodes.
    keyboardObjectnone + Configuration options for shortcuts keys. Shortcut keys are turned off by default. See section Keyboard navigation for an overview of the available options. +
    dragNetworkBooleantrue + Toggle if the network can be dragged. This will not affect the dragging of nodes. +
    dragNodesBooleantrue + Toggle if the nodes can be dragged. This will not affect the dragging of the network. +
    hideNodesOnDragBooleanfalse + Toggle if the nodes are drawn during a drag. This can greatly improve performance if you have many nodes. +
    hideEdgesOnDragBooleanfalse + Toggle if the edges are drawn during a drag. This can greatly improve performance if you have many edges. +
    navigationObjectnone + Configuration options for the navigation controls. See section Navigation controls for an overview of the available options. +
    stabilizeBooleantrueIf true, the network is stabilized before displaying it. If false, - the nodes move to a stabe position visibly in an animated way.
    nodesObjectnone + Configuration options applied to all nodes. See section Nodes configuration for an overview of the available options. +
    stabilizationIterationsNumber1000If stabilize is set to true, this number is the (maximum) amount of physics steps the stabilization process takes - before showing the result. If your simulation takes too long to stabilize, this number can be reduced. On the other hand, if your network is not stabilized after loading, this number can be increased.smoothCurvesBoolean || objectobjectIf true, edges are drawn as smooth curves. This is more computationally intensive since the edge now is a quadratic Bezier curve. This can be further configured by the options below.
    widthString"400px"The width of the network in pixels or as a percentage.
    zoomableBooleantrue - Toggle if the network can be zoomed. -
    smoothCurves.dynamicBooleantrueBy default, the edges are dynamic. This means there are support nodes placed in the middle of the edge. This support node is also handed by the physics simulation. If false, the smoothness will be based on the + relative positions of the to and from nodes. This is computationally cheaper but there is no self organisation.
    smoothCurves.typeString"continuous"This option only affects NONdynamic smooth curves. The supported types are: continuous, discrete, diagonalCross, straightCross, horizontal, vertical. The effects of these types + are shown in examples 26 and 27
    smoothCurves.roundnessNumber0.5This only affects NONdynamic smooth curves. The roundness can be tweaked with the parameter. The value range is from 0 to 1 with a maximum roundness at 0.5.
    selectableBooleantrueIf true, nodes in the network can be selected by clicking them. + Long press can be used to select multiple nodes.
    stabilizeBooleantrueIf true, the network is stabilized before displaying it. If false, + the nodes move to a stabe position visibly in an animated way.
    stabilizationIterationsNumber1000If stabilize is set to true, this number is the (maximum) amount of physics steps the stabilization process takes + before showing the result. If your simulation takes too long to stabilize, this number can be reduced. On the other hand, if your network is not stabilized after loading, this number can be increased.
    widthString"400px"The width of the network in pixels or as a percentage.
    zoomableBooleantrue + Toggle if the network can be zoomed. +
    @@ -1149,22 +1149,22 @@ var options = { "#2B7CE9" Default border color of the node when selected. - - allowedToMoveX - Boolean - false - If allowedToMoveX is false, then the node will not move from its supplied position. - If an X position has been supplied, it is fixed in the X-direction. - If no X value has been supplied, this argument will not do anything. - - - allowedToMoveY - Boolean - false - If allowedToMoveY is false, then the node will not move from its supplied position. - If an Y position has been supplied, it is fixed in the Y-direction. - If no Y value has been supplied, this argument will not do anything. - + + allowedToMoveX + Boolean + false + If allowedToMoveX is false, then the node will not move from its supplied position. + If an X position has been supplied, it is fixed in the X-direction. + If no X value has been supplied, this argument will not do anything. + + + allowedToMoveY + Boolean + false + If allowedToMoveY is false, then the node will not move from its supplied position. + If an Y position has been supplied, it is fixed in the Y-direction. + If no Y value has been supplied, this argument will not do anything. + fontColor @@ -1196,19 +1196,19 @@ var options = { none Default image url for the nodes. only applicable to shape image. - - mass - number - 1 - When using the Barnes Hut simulation method (which is selected by default), - the mass of a node determines the gravitational repulsion during the simulation. Higher mass will push other nodes further away. - - - level - number - -1 - This level is used in the hierarchical layout. If this is not selected, the level does not do anything. - + + mass + number + 1 + When using the Barnes Hut simulation method (which is selected by default), + the mass of a node determines the gravitational repulsion during the simulation. Higher mass will push other nodes further away. + + + level + number + -1 + This level is used in the hierarchical layout. If this is not selected, the level does not do anything. + widthMin Number @@ -1262,7 +1262,7 @@ var options = {

    Edges can be configured with different length and styling. To configure edges, provide an object named edges in the options for the Network. Because the length of an edge is a property of the physics simulation, you can change the length of the edge by changing the springLength in your selected physics solver. - To change the edge length of individual edges, you can use the length property in the edge definition. + To change the edge length of individual edges, you can use the length property in the edge definition.

    @@ -1356,13 +1356,13 @@ var options = { Only applicable when the line style is dash-line. - - inheritColor - String | Boolean - false - Possible values: "to","from", true, false. If this value is set to false, the edge color information is used. If the value is set to true or "from", - the color data from the borders of the "from" node is used. If this value is "to", the color data from the borders of the "to" node is used. - + + inheritColor + String | Boolean + false + Possible values: "to","from", true, false. If this value is set to false, the edge color information is used. If the value is set to true or "from", + the color data from the borders of the "from" node is used. If this value is "to", the color data from the borders of the "to" node is used. + style @@ -1524,11 +1524,11 @@ var nodes = [

    Physics

    - The original simulation method was based on particel physics with a repulsion field (potential) around each node, - and the edges were modelled as springs. The new system employed the Barnes-Hut gravitational simulation model. The edges are still modelled as springs. - To unify the physics system, the damping, repulsion distance and edge length have been combined in an physics option. To retain good behaviour, both the old repulsion model and the Barnes-Hut model have their own parameters. - If no options for the physics system are supplied, the Barnes-Hut method will be used with the default parameters. If you want to customize the physics system easily, you can use the configurePhysics option.
    - When using the hierarchical display option, hierarchicalRepulsion is automatically used as the physics solver. Similarly, if you use the hierarchicalRepulsion physics option, hierarchical display is automatically turned on with default settings. + The original simulation method was based on particel physics with a repulsion field (potential) around each node, + and the edges were modelled as springs. The new system employed the Barnes-Hut gravitational simulation model. The edges are still modelled as springs. + To unify the physics system, the damping, repulsion distance and edge length have been combined in an physics option. To retain good behaviour, both the old repulsion model and the Barnes-Hut model have their own parameters. + If no options for the physics system are supplied, the Barnes-Hut method will be used with the default parameters. If you want to customize the physics system easily, you can use the configurePhysics option.
    + When using the hierarchical display option, hierarchicalRepulsion is automatically used as the physics solver. Similarly, if you use the hierarchicalRepulsion physics option, hierarchical display is automatically turned on with default settings.

    Note: if the behaviour of your network is not the way you want it, use configurePhysics as described below or by example 25.

    @@ -1563,135 +1563,135 @@ var options = {
    barnesHut:
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    NameTypeDefaultDescription
    enabledBooleantrueThis switches the Barnes-Hut simulation on or off. If it is turned off, the old repulsion model is used. Barnes-Hut is generally faster and yields better results.
    gravitationalConstantNumber-2000This is the gravitational constand used to calculate the gravity forces. More information is available here.
    centralGravityNumber0.1The central gravity is a force that pulls all nodes to the center. This ensures independent groups do not float apart.
    springLengthNumber95In the previous versions this was a property of the edges, called length. This is the length of the springs when they are at rest. During the simulation they will be streched by the gravitational fields. - To greatly reduce the edge length, the gravitationalConstant has to be reduced as well.
    springConstantNumber0.04This is the spring constant used to calculate the spring forces based on Hooke′s Law. More information is available here.
    dampingNumber0.09This is the damping constant. It is used to dissipate energy from the system to have it settle in an equilibrium. More information is available here.
    NameTypeDefaultDescription
    enabledBooleantrueThis switches the Barnes-Hut simulation on or off. If it is turned off, the old repulsion model is used. Barnes-Hut is generally faster and yields better results.
    gravitationalConstantNumber-2000This is the gravitational constand used to calculate the gravity forces. More information is available here.
    centralGravityNumber0.1The central gravity is a force that pulls all nodes to the center. This ensures independent groups do not float apart.
    springLengthNumber95In the previous versions this was a property of the edges, called length. This is the length of the springs when they are at rest. During the simulation they will be streched by the gravitational fields. + To greatly reduce the edge length, the gravitationalConstant has to be reduced as well.
    springConstantNumber0.04This is the spring constant used to calculate the spring forces based on Hooke′s Law. More information is available here.
    dampingNumber0.09This is the damping constant. It is used to dissipate energy from the system to have it settle in an equilibrium. More information is available here.
    repulsion:
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    NameTypeDefaultDescription
    centralGravityNumber0.1The central gravity is a force that pulls all nodes to the center. This ensures independent groups do not float apart.
    nodeDistanceNumber100This parameter is used to define the distance of influence of the repulsion field of the nodes. Below half this distance, the repulsion is maximal and beyond twice this distance the repulsion is zero.
    springLengthNumber50In the previous versions this was a property of the edges, called length. This is the length of the springs when they are at rest. During the simulation they will be streched by the gravitational fields. - To greatly reduce the edge length, the gravitationalConstant has to be reduced as well.
    springConstantNumber0.05This is the spring constant used to calculate the spring forces based on Hooke′s Law. More information is available here.
    dampingNumber0.09This is the damping constant. It is used to dissipate energy from the system to have it settle in an equilibrium. More information is available here.
    NameTypeDefaultDescription
    centralGravityNumber0.1The central gravity is a force that pulls all nodes to the center. This ensures independent groups do not float apart.
    nodeDistanceNumber100This parameter is used to define the distance of influence of the repulsion field of the nodes. Below half this distance, the repulsion is maximal and beyond twice this distance the repulsion is zero.
    springLengthNumber50In the previous versions this was a property of the edges, called length. This is the length of the springs when they are at rest. During the simulation they will be streched by the gravitational fields. + To greatly reduce the edge length, the gravitationalConstant has to be reduced as well.
    springConstantNumber0.05This is the spring constant used to calculate the spring forces based on Hooke′s Law. More information is available here.
    dampingNumber0.09This is the damping constant. It is used to dissipate energy from the system to have it settle in an equilibrium. More information is available here.
    hierarchicalRepulsion:
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    NameTypeDefaultDescription
    centralGravityNumber0.5The central gravity is a force that pulls all nodes to the center. This ensures independent groups do not float apart.
    nodeDistanceNumber60This parameter is used to define the distance of influence of the repulsion field of the nodes. Below half this distance, the repulsion is maximal and beyond twice this distance the repulsion is zero.
    springLengthNumber100In the previous versions this was a property of the edges, called length. This is the length of the springs when they are at rest. During the simulation they will be streched by the gravitational fields. - To greatly reduce the edge length, the gravitationalConstant has to be reduced as well.
    springConstantNumber0.01This is the spring constant used to calculate the spring forces based on Hooke′s Law. More information is available here.
    dampingNumber0.09This is the damping constant. It is used to dissipate energy from the system to have it settle in an equilibrium. More information is available here.
    NameTypeDefaultDescription
    centralGravityNumber0.5The central gravity is a force that pulls all nodes to the center. This ensures independent groups do not float apart.
    nodeDistanceNumber60This parameter is used to define the distance of influence of the repulsion field of the nodes. Below half this distance, the repulsion is maximal and beyond twice this distance the repulsion is zero.
    springLengthNumber100In the previous versions this was a property of the edges, called length. This is the length of the springs when they are at rest. During the simulation they will be streched by the gravitational fields. + To greatly reduce the edge length, the gravitationalConstant has to be reduced as well.
    springConstantNumber0.01This is the spring constant used to calculate the spring forces based on Hooke′s Law. More information is available here.
    dampingNumber0.09This is the damping constant. It is used to dissipate energy from the system to have it settle in an equilibrium. More information is available here.

    Configuration:

    Every dataset is different. Nodes can have different sizes based on content, interconnectivity can be high or low etc. Because of this, network has a special option @@ -1706,11 +1706,11 @@ var options = {

    Data manipulation

    - By using the data manipulation feature of the network you can dynamically create nodes, connect nodes with edges, edit nodes or delete nodes and edges. - The toolbar is fully HTML and CSS so the user can style this to their preference. To control the behaviour of the data manipulation, users can insert custom functions - into the data manipulation process. For example, an injected function can show an detailed pop-up when a user wants to add a node. In example 21, - two functions have been injected into the add and edit functionality. This is described in more detail in the next subsection. To correctly display the manipulation icons, the vis.css file must be included. - The user is free to alter or overload the CSS classes but without them the navigation icons are not visible. + By using the data manipulation feature of the network you can dynamically create nodes, connect nodes with edges, edit nodes or delete nodes and edges. + The toolbar is fully HTML and CSS so the user can style this to their preference. To control the behaviour of the data manipulation, users can insert custom functions + into the data manipulation process. For example, an injected function can show an detailed pop-up when a user wants to add a node. In example 21, + two functions have been injected into the add and edit functionality. This is described in more detail in the next subsection. To correctly display the manipulation icons, the vis.css file must be included. + The user is free to alter or overload the CSS classes but without them the navigation icons are not visible.

     // These variables must be defined in an options object named dataManipulation.
    @@ -1727,36 +1727,36 @@ var options: {
     }
     
    - + - + - + - - + + - +
    Name Type Default Description
    enabled Boolean false Enabling or disabling of the data manipulation toolbar. If it is initially hidden, an edit button appears in the top left corner.
    initiallyVisible Boolean false Initially hide or show the data manipulation toolbar.

    Data manipulation: custom functionality

    - Users can insert custom functions into the add node, edit node, connect nodes, and delete selected operations. This is done by supplying them in the options. - If the callback is NOT called, nothing happens. Example 21 has two working examples - for the add and edit functions. The data the user is supplied with in these functions has been described in the code below. - For the add data, you can add any and all options that are accepted for node creation as described above. The same goes for edit, however only the fields described - in the code below contain information on the selected node. The callback for connect accepts any options that are used for edge creation. Only the callback for delete selected - requires the same data structure that is supplied to the user.

    - If there is no injected function supplied for the edit operation, the button will not be shown in the toolbar. + Users can insert custom functions into the add node, edit node, connect nodes, and delete selected operations. This is done by supplying them in the options. + If the callback is NOT called, nothing happens. Example 21 has two working examples + for the add and edit functions. The data the user is supplied with in these functions has been described in the code below. + For the add data, you can add any and all options that are accepted for node creation as described above. The same goes for edit, however only the fields described + in the code below contain information on the selected node. The callback for connect accepts any options that are used for edge creation. Only the callback for delete selected + requires the same data structure that is supplied to the user.

    + If there is no injected function supplied for the edit operation, the button will not be shown in the toolbar.

     // If a variable is not supplied, the default value is used.
    @@ -1818,9 +1818,9 @@ var options: {
     };
     

    - Because the interface elements are CSS and HTML, the user will have to correct for size changes of the canvas. To facilitate this, a new event has been added called resize. - A function can be bound to this event. This function is supplied with the new widht and height of the canvas. The CSS can then be updated accordingly. - An code snippet from example 21 is shown below. + Because the interface elements are CSS and HTML, the user will have to correct for size changes of the canvas. To facilitate this, a new event has been added called resize. + A function can be bound to this event. This function is supplied with the new widht and height of the canvas. The CSS can then be updated accordingly. + An code snippet from example 21 is shown below.

     network.on("resize", function(params) {console.log(params.width,params.height)});
    @@ -1940,12 +1940,12 @@ var options: {
         4.0
         This parameter denotes the increase in fontSize of the cluster when a single node is added to it.
       
    -    
    -        maxFontSize
    -        Number
    -        1000
    -        This parameter denotes the largest allowed font size. If the font becomes too large, some browsers experience problems displaying this.
    -    
    +  
    +    maxFontSize
    +    Number
    +    1000
    +    This parameter denotes the largest allowed font size. If the font becomes too large, some browsers experience problems displaying this.
    +  
       
         forceAmplification
         Number
    @@ -1985,29 +1985,29 @@ var options: {
         10
         This factor determines how much the radius of a cluster increases in pixels per added node.
       
    -    
    -        maxNodeSizeIncrements
    -        Number
    -        600
    -        This limits the size clusters can grow to. The default value, 600, implies that if a cluster contains more than 600 nodes, it will no longer grow.
    -    
    -    
    -        activeAreaBoxSize
    -        Number
    -        100
    -        Imagine a square with an edge length of activeAreaBoxSize pixels around your cursor.
    -            If a cluster is in this box as you zoom in, the cluster can be opened in a seperate sector.
    -            This is regardless of the zoom level.
    -    
    +  
    +    maxNodeSizeIncrements
    +    Number
    +    600
    +    This limits the size clusters can grow to. The default value, 600, implies that if a cluster contains more than 600 nodes, it will no longer grow.
    +  
    +  
    +    activeAreaBoxSize
    +    Number
    +    100
    +    Imagine a square with an edge length of activeAreaBoxSize pixels around your cursor.
    +      If a cluster is in this box as you zoom in, the cluster can be opened in a seperate sector.
    +      This is regardless of the zoom level.
    +  
       
         clusterLevelDifference
         Number
         2
         At every clustering session, Network will check if the difference between cluster levels is
    -        acceptable. When a cluster is formed when zooming out, that is one cluster level.
    -        If you zoom out further and it encompasses more nodes, that is another level. For example:
    -        If the highest level of your network at any given time is 3, nodes that have not clustered or
    -        have clustered only once will join their neighbour with the lowest cluster level.
    +      acceptable. When a cluster is formed when zooming out, that is one cluster level.
    +      If you zoom out further and it encompasses more nodes, that is another level. For example:
    +      If the highest level of your network at any given time is 3, nodes that have not clustered or
    +      have clustered only once will join their neighbour with the lowest cluster level.
       
     
     
    @@ -2015,7 +2015,7 @@ var options: {
     

    Network has a menu with navigation controls, which is disabled by default. It can be configured with the following settings. To correctly display the navigation icons, the vis.css file must be included. - The user is free to alter or overload the CSS classes but without them the navigation icons are not visible. + The user is free to alter or overload the CSS classes but without them the navigation icons are not visible.

    @@ -2082,10 +2082,10 @@ var options: {
     
     

    Hierarchical layout

    - The network can be used to display nodes in a hierarchical way. This can be determined automatically, based on the amount of edges connected to each node, or defined by the user. - If the user wants to manually determine the hierarchy, each node has to be supplied with a level (from 0 being heighest to n). The automatic method - is shown in example 23 and the user-defined method is shown in example 24. - This layout method does not support smooth curves or clustering. It automatically turns these features off. + The network can be used to display nodes in a hierarchical way. This can be determined automatically, based on the amount of edges connected to each node, or defined by the user. + If the user wants to manually determine the hierarchy, each node has to be supplied with a level (from 0 being heighest to n). The automatic method + is shown in example 23 and the user-defined method is shown in example 24. + This layout method does not support smooth curves or clustering. It automatically turns these features off.

    @@ -2113,90 +2113,131 @@ var options: {
     
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    NameTypeDefaultDescription
    enabledBooleanfalseEnable or disable the hierarchical layout. -
    levelSeparationNumber150This defines the space between levels (in the Y-direction, considering UP-DOWN direction).
    nodeSpacingNumber100This defines the space between nodes in the same level (in the X-direction, considering UP-DOWN direction). - This is only relevant during the initial placing of nodes.
    directionStringUDThis defines the direction the network is drawn in. The supported directions are: Up-Down (UD), Down-Up (DU), Left-Right (LR) and Right-Left (RL). - These need to be supplied by the acronyms in parentheses.
    NameTypeDefaultDescription
    enabledBooleanfalseEnable or disable the hierarchical layout. +
    levelSeparationNumber150This defines the space between levels (in the Y-direction, considering UP-DOWN direction).
    nodeSpacingNumber100This defines the space between nodes in the same level (in the X-direction, considering UP-DOWN direction). + This is only relevant during the initial placing of nodes.
    directionStringUDThis defines the direction the network is drawn in. The supported directions are: Up-Down (UD), Down-Up (DU), Left-Right (LR) and Right-Left (RL). + These need to be supplied by the acronyms in parentheses.

    Localization

    - When using vis.js in other languages, one can use the localization option to overwrite the labels used in the data manipulation interface. + When using vis.js in other languages, one can use the localization option to get a localized data manipulation interface.

    -
    -var options: {
    -    labels:{
    -      add:"Add Node",
    -      edit:"Edit",
    -      link:"Add Link",
    -      del:"Delete selected",
    -      editNode:"Edit Node",
    -      editEdge:"Edit Edge",
    -      back:"Back",
    -      addDescription:"Click in an empty space to place a new node.",
    -      linkDescription:"Click on a node and drag the edge to another
    -                       node to connect them.",
    -      editEdgeDescription:"Click on either one of the control points and drag them to another node to connect to it.".
    -      addError:"The function for add does not support two arguments
    -                                                        (data,callback).",
    -      linkError:"The function for connect does not support two arguments
    -                                                        (data,callback).",
    -      editError:"The function for edit does not support two arguments
    -                                                        (data, callback).",
    -      editBoundError:"No edit function has been bound to this button.",
    -      deleteError:"The function for delete does not support two arguments
    -                                                        (data, callback).",
    -      deleteClusterError:"Clusters cannot be deleted."
    +
    +  
    +    
    +    
    +    
    +    
    +  
    +
    +  
    +    
    +    
    +    
    +    
    +  
    +
    +  
    +    
    +    
    +    
    +    
    +  
    +
    NameTypeDefaultDescription
    localeStringnoneSelect a locale for the Network.
    localesObjectnoneA map with i18n locales.
    + +

    + To set a locale for the Network, specify the option locale: +

    + +
    var options = {
    +  locale: 'nl'
    +};
    +
    + +

    Create a new locale

    + +To load a locale into the Timeline not supported by default, one can add a new locale to the option locales: + +
    var options = {
    +  locales: {
    +    // create a new locale (text strings should be replaced with localized strings)
    +    mylocale: {
    +      add: 'Add Node',
    +      edit: 'Edit',
    +      link: 'Add Link',
    +      del: 'Delete selected',
    +      editNode: 'Edit Node',
    +      editEdge: 'Edit Edge',
    +      back: 'Back',
    +      addDescription: 'Click in an empty space to place a new node.',
    +      linkDescription: 'Click on a node and drag the edge to another node to connect them.',
    +      editEdgeDescription: 'Click on the control points and drag them to a node to connect to it.',
    +      createEdgeError: 'Cannot link edges to a cluster.',
    +      deleteClusterError: 'Clusters cannot be deleted.'
         }
    -}
    +  },
    +
    +  // use the new locale
    +  locale: 'mylocale'
    +};
     
    +

    Available locales

    + +

    + Network comes with support for the following locales: +

    + - - - - - - - - - - - - - + + + + + + + + +
    NameTypeDefaultDescription
    labelsobject(shown above)Overwrite one or all labels used in the datamanipulation interface with localized strings. -
    LanguageCode
    English + en
    + en_EN
    + en_US +
    Dutch + nl
    + nl_NL
    + nl_BE +

    Tooltips

    @@ -2287,32 +2328,32 @@ var options: { The selections are not ordered. - - focusOnNode(nodeId, [zoomLevel]) - none - This function will move the view to center on the specified node. An optional zoomLevel can be passed where 1.0 is 100%, between 0.0 and 1.0 is zooming out and > 1.0 is zooming in. Generally, close to 1.0 is sufficient. - If this argument is not passed the view will only move, not zoom. - - - - storePosition() - none - This will put the X and Y positions of all nodes in the dataset. It will also include allowedToMoveX and allowedToMoveY with the correct values. - You can use this to stablize your network once, then save the positions in a database so the next time you load the nodes, stabilization will be near instantaneous. - - - - DOMtoCanvas(pos) - object - This function converts DOM coordinates to coordinates on the canvas. Input and output are in the form of {x:xpos,y:ypos}. The DOM values are relative to the network container. - - - - canvasToDOM(pos) - object - This function converts canvas coordinates to coordinates on the DOM. Input and output are in the form of {x:xpos,y:ypos}. The DOM values are relative to the network container. - - + + focusOnNode(nodeId, [zoomLevel]) + none + This function will move the view to center on the specified node. An optional zoomLevel can be passed where 1.0 is 100%, between 0.0 and 1.0 is zooming out and > 1.0 is zooming in. Generally, close to 1.0 is sufficient. + If this argument is not passed the view will only move, not zoom. + + + + storePosition() + none + This will put the X and Y positions of all nodes in the dataset. It will also include allowedToMoveX and allowedToMoveY with the correct values. + You can use this to stablize your network once, then save the positions in a database so the next time you load the nodes, stabilization will be near instantaneous. + + + + DOMtoCanvas(pos) + object + This function converts DOM coordinates to coordinates on the canvas. Input and output are in the form of {x:xpos,y:ypos}. The DOM values are relative to the network container. + + + + canvasToDOM(pos) + object + This function converts canvas coordinates to coordinates on the DOM. Input and output are in the form of {x:xpos,y:ypos}. The DOM values are relative to the network container. + + on(event, callback) none @@ -2350,36 +2391,36 @@ var options: { - - selectNodes(selection, [highlightEdges]) - none - Select nodes. - selection is an array with ids of nodes to be selected. - The array selection can contain zero or multiple ids. - Example usage: network.selectNodes([3, 5]); will select - nodes with id 3 and 5. The highlisghEdges boolean can be used to automatically select the edges connected to the node. - - - - selectEdges(selection) - none - Select Edges. - selection is an array with ids of edges to be selected. - The array selection can contain zero or multiple ids. - Example usage: network.selectEdges([3, 5]); will select - edges with id 3 and 5. - - + + selectNodes(selection, [highlightEdges]) + none + Select nodes. + selection is an array with ids of nodes to be selected. + The array selection can contain zero or multiple ids. + Example usage: network.selectNodes([3, 5]); will select + nodes with id 3 and 5. The highlisghEdges boolean can be used to automatically select the edges connected to the node. + + + + selectEdges(selection) + none + Select Edges. + selection is an array with ids of edges to be selected. + The array selection can contain zero or multiple ids. + Example usage: network.selectEdges([3, 5]); will select + edges with id 3 and 5. + + setSelection(selection) none Select nodes [deprecated]. - selection is an array with ids of nodes to be selected. - The array selection can contain zero or multiple ids. - Example usage: network.setSelection([3, 5]); will select - nodes with id 3 and 5. + selection is an array with ids of nodes to be selected. + The array selection can contain zero or multiple ids. + Example usage: network.setSelection([3, 5]); will select + nodes with id 3 and 5. - + setSize(width, height) @@ -2389,11 +2430,11 @@ var options: { or in percentages. - - zoomExtent() - none - Scales the network so all the nodes are in center view. - + + zoomExtent() + none + Scales the network so all the nodes are in center view. + @@ -2455,82 +2496,82 @@ network.off('select', onSelect); - - click - Fired after the user clicks or taps on a touchscreen. - -
      -
    • nodes: an array with the ids of the selected nodes
    • -
    • edges: an array with the ids of the selected edges
    • -
    - - - - doubleClick - Fired after the user double clicks or double taps on a touchscreen. - -
      -
    • nodes: an array with the ids of the selected nodes
    • -
    • edges: an array with the ids of the selected edges
    • -
    - - - - - hoverNode - Fired when the mouse is moved over a node (assuming the hover option is enabled). - -
      -
    • node: an object with the id of the hovered node.
    • -
    - - - - - blurNode - Fired when the mouse is moved off a node (assuming the hover option is enabled). - -
      -
    • node: an object with the id of the hovered node.
    • -
    - - - - resize - Fired when the size of the canvas has been updated (not neccecarily changed) by the setSize() function or by the setOptions() function. - -
      -
    • width: the new width of the canvas
    • -
    • height: the new height of the canvas
    • -
    - - - - stabilized - Fired when the network has been stabilized. This event can be used to trigger the .storePosition() function after stabilization. When the network in initialized, the parameter - iterations will be the amount of iterations it took to stabilize. After initialization, this parameter is null. - -
      -
    • iterations: number of iterations used to stabilize
    • -
    - - - - viewChanged - Fired when the view has changed. This is when the network has moved or zoomed. - - none - - - - zoom - Fired when the network has zoomed. This event can be used to trigger the .storePosition() function after stabilization. - -
      -
    • direction: "+" or "-"
    • -
    - - + + click + Fired after the user clicks or taps on a touchscreen. + +
      +
    • nodes: an array with the ids of the selected nodes
    • +
    • edges: an array with the ids of the selected edges
    • +
    + + + + doubleClick + Fired after the user double clicks or double taps on a touchscreen. + +
      +
    • nodes: an array with the ids of the selected nodes
    • +
    • edges: an array with the ids of the selected edges
    • +
    + + + + + hoverNode + Fired when the mouse is moved over a node (assuming the hover option is enabled). + +
      +
    • node: an object with the id of the hovered node.
    • +
    + + + + + blurNode + Fired when the mouse is moved off a node (assuming the hover option is enabled). + +
      +
    • node: an object with the id of the hovered node.
    • +
    + + + + resize + Fired when the size of the canvas has been updated (not neccecarily changed) by the setSize() function or by the setOptions() function. + +
      +
    • width: the new width of the canvas
    • +
    • height: the new height of the canvas
    • +
    + + + + stabilized + Fired when the network has been stabilized. This event can be used to trigger the .storePosition() function after stabilization. When the network in initialized, the parameter + iterations will be the amount of iterations it took to stabilize. After initialization, this parameter is null. + +
      +
    • iterations: number of iterations used to stabilize
    • +
    + + + + viewChanged + Fired when the view has changed. This is when the network has moved or zoomed. + + none + + + + zoom + Fired when the network has zoomed. This event can be used to trigger the .storePosition() function after stabilization. + +
      +
    • direction: "+" or "-"
    • +
    + + diff --git a/docs/timeline.html b/docs/timeline.html index fdba8c52..d08677c8 100644 --- a/docs/timeline.html +++ b/docs/timeline.html @@ -443,14 +443,14 @@ var options = { locale String none - Select a locale for the Timeline. See section Localization for more information. + Select a locale for the Timeline. See section Localization for more information. locales Object none - A map with i18n locales. See section Localization for more information. + A map with i18n locales. See section Localization for more information. @@ -1025,7 +1025,7 @@ To load a locale into the Timeline not supported by default, one can add a new l
    var options = {
       locales: {
    -    // create a new locale
    +    // create a new locale (text strings should be replaced with localized strings)
         mylocale: {
           current: 'current',
           time: 'time',
    @@ -1039,7 +1039,9 @@ To load a locale into the Timeline not supported by default, one can add a new l
     
     

    Available locales

    -Timeline comes with support for the following locales: +

    + Timeline comes with support for the following locales: +

    diff --git a/examples/network/31_localization.html b/examples/network/31_localization.html new file mode 100644 index 00000000..4654caa7 --- /dev/null +++ b/examples/network/31_localization.html @@ -0,0 +1,231 @@ + + + + Network | Localization + + + + + + + + + +

    Editing the dataset (localized)

    +

    + This is the same example as 21_data_manipulation.html, except that there is a select box added which allows to switch locale. The localization is only relevant to the manipulation buttons. +

    + +

    + + +

    + +
    + node
    +
    LanguageCode
    + + + + +
    id
    label
    + + + +
    +
    + +

    + + + diff --git a/examples/network/index.html b/examples/network/index.html index 5d815172..69c237ac 100644 --- a/examples/network/index.html +++ b/examples/network/index.html @@ -42,6 +42,7 @@

    28_world_cup_network_performance.html

    29_neighbourhood_highlight.html

    30_importing_from_gephi.html

    +

    31_localization.html

    graphviz_gallery.html

    diff --git a/lib/network/Network.js b/lib/network/Network.js index 8e9a39c5..22a0646f 100644 --- a/lib/network/Network.js +++ b/lib/network/Network.js @@ -13,6 +13,7 @@ var Node = require('./Node'); var Edge = require('./Edge'); var Popup = require('./Popup'); var MixinLoader = require('./mixins/MixinLoader'); +var locales = require('./locales'); // Load custom shapes into CanvasRenderingContext2D require('./shapes'); @@ -188,25 +189,8 @@ function Network (container, data, options) { minVelocity: 0.1, // px/s stabilize: true, // stabilize before displaying the network stabilizationIterations: 1000, // maximum number of iteration to stabilize - labels:{ - add:"Add Node", - edit:"Edit", - link:"Add Link", - del:"Delete selected", - editNode:"Edit Node", - editEdge:"Edit Edge", - back:"Back", - addDescription:"Click in an empty space to place a new node.", - linkDescription:"Click on a node and drag the edge to another node to connect them.", - editEdgeDescription:"Click on the control points and drag them to a node to connect to it.", - addError:"The function for add does not support two arguments (data,callback).", - linkError:"The function for connect does not support two arguments (data,callback).", - editError:"The function for edit does not support two arguments (data, callback).", - editBoundError:"No edit function has been bound to this button.", - deleteError:"The function for delete does not support two arguments (data, callback).", - createEdgeError:"Cannot link edges to a cluster.", - deleteClusterError:"Clusters cannot be deleted." - }, + locale: 'en', + locales: locales, tooltip: { delay: 300, fontColor: 'black', @@ -663,6 +647,10 @@ Network.prototype.setOptions = function (options) { this.constants.tooltip.color = util.parseColor(options.tooltip.color); } } + + if (options.labels) { + throw new Error('Option "labels" is deprecated. Use options "locale" and "locales" instead.'); + } } // (Re)loading the mixins that can be enabled or disabled in the options. diff --git a/lib/network/locales.js b/lib/network/locales.js index 805cd542..f29653de 100644 --- a/lib/network/locales.js +++ b/lib/network/locales.js @@ -10,8 +10,8 @@ exports['en'] = { addDescription: 'Click in an empty space to place a new node.', linkDescription: 'Click on a node and drag the edge to another node to connect them.', editEdgeDescription: 'Click on the control points and drag them to a node to connect to it.', - createEdgeError:"Cannot link edges to a cluster.", - deleteClusterError:"Clusters cannot be deleted." + createEdgeError: 'Cannot link edges to a cluster.', + deleteClusterError: 'Clusters cannot be deleted.' }; exports['en_EN'] = exports['en']; exports['en_US'] = exports['en']; diff --git a/lib/network/mixins/ManipulationMixin.js b/lib/network/mixins/ManipulationMixin.js index b4bebea8..5d12bc50 100644 --- a/lib/network/mixins/ManipulationMixin.js +++ b/lib/network/mixins/ManipulationMixin.js @@ -64,6 +64,8 @@ exports._createManipulatorBar = function() { this.off('select', this.boundFunction); } + var locale = this.constants.locales[this.constants.locale]; + if (this.edgeBeingEdited !== undefined) { this.edgeBeingEdited._disableControlNodes(); this.edgeBeingEdited = undefined; @@ -85,30 +87,31 @@ exports._createManipulatorBar = function() { while (this.manipulationDiv.hasChildNodes()) { this.manipulationDiv.removeChild(this.manipulationDiv.firstChild); } + // add the icons to the manipulator div this.manipulationDiv.innerHTML = "" + "" + - ""+this.constants.labels['add'] +"" + + ""+locale['add'] +"" + "
    " + "" + - ""+this.constants.labels['link'] +""; + ""+locale['link'] +""; if (this._getSelectedNodeCount() == 1 && this.triggerFunctions.edit) { this.manipulationDiv.innerHTML += "" + "
    " + "" + - ""+this.constants.labels['editNode'] +""; + ""+locale['editNode'] +""; } else if (this._getSelectedEdgeCount() == 1 && this._getSelectedNodeCount() == 0) { this.manipulationDiv.innerHTML += "" + "
    " + "" + - ""+this.constants.labels['editEdge'] +""; + ""+locale['editEdge'] +""; } if (this._selectionIsEmpty() == false) { this.manipulationDiv.innerHTML += "" + "
    " + "" + - ""+this.constants.labels['del'] +""; + ""+locale['del'] +""; } @@ -138,7 +141,7 @@ exports._createManipulatorBar = function() { else { this.editModeDiv.innerHTML = "" + "" + - "" + this.constants.labels['edit'] + ""; + "" + locale['edit'] + ""; var editModeButton = document.getElementById("network-manipulate-editModeButton"); editModeButton.onclick = this._toggleEditMode.bind(this); } @@ -158,13 +161,15 @@ exports._createAddNodeToolbar = function() { this.off('select', this.boundFunction); } + var locale = this.constants.locales[this.constants.locale]; + // create the toolbar contents this.manipulationDiv.innerHTML = "" + "" + - "" + this.constants.labels['back'] + " " + + "" + locale['back'] + " " + "
    " + "" + - "" + this.constants.labels['addDescription'] + ""; + "" + locale['addDescription'] + ""; // bind the icon var backButton = document.getElementById("network-manipulate-back"); @@ -187,6 +192,8 @@ exports._createAddEdgeToolbar = function() { this._unselectAll(true); this.freezeSimulation = true; + var locale = this.constants.locales[this.constants.locale]; + if (this.boundFunction) { this.off('select', this.boundFunction); } @@ -197,10 +204,10 @@ exports._createAddEdgeToolbar = function() { this.manipulationDiv.innerHTML = "" + "" + - "" + this.constants.labels['back'] + " " + + "" + locale['back'] + " " + "
    " + "" + - "" + this.constants.labels['linkDescription'] + ""; + "" + locale['linkDescription'] + ""; // bind the icon var backButton = document.getElementById("network-manipulate-back"); @@ -237,12 +244,14 @@ exports._createEditEdgeToolbar = function() { this.edgeBeingEdited = this._getSelectedEdge(); this.edgeBeingEdited._enableControlNodes(); + var locale = this.constants.locales[this.constants.locale]; + this.manipulationDiv.innerHTML = "" + "" + - "" + this.constants.labels['back'] + " " + + "" + locale['back'] + " " + "
    " + "" + - "" + this.constants.labels['editEdgeDescription'] + ""; + "" + locale['editEdgeDescription'] + ""; // bind the icon var backButton = document.getElementById("network-manipulate-back"); @@ -328,9 +337,10 @@ exports._releaseControlNode = function(pointer) { exports._handleConnect = function(pointer) { if (this._getSelectedNodeCount() == 0) { var node = this._getNodeAt(pointer); + if (node != null) { if (node.clusterSize > 1) { - alert(this.constants.labels["createEdgeError"]) + alert(this.constants.locales[this.constants.locale]['createEdgeError']) } else { this._selectObject(node,false); @@ -386,7 +396,7 @@ exports._finishConnect = function(pointer) { var node = this._getNodeAt(pointer); if (node != null) { if (node.clusterSize > 1) { - alert(this.constants.labels["createEdgeError"]) + alert(this.constants.locales[this.constants.locale]["createEdgeError"]) } else { this._createEdge(connectFromId,node.id); @@ -416,7 +426,7 @@ exports._addNode = function() { }); } else { - throw new Error(this.constants.labels['addError']); + throw new Error('The function for add does not support two arguments (data,callback)'); this._createManipulatorBar(); this.moving = true; this.start(); @@ -450,7 +460,7 @@ exports._createEdge = function(sourceNodeId,targetNodeId) { }); } else { - throw new Error(this.constants.labels["linkError"]); + throw new Error('The function for connect does not support two arguments (data,callback)'); this.moving = true; this.start(); } @@ -481,7 +491,7 @@ exports._editEdge = function(sourceNodeId,targetNodeId) { }); } else { - throw new Error(this.constants.labels["linkError"]); + throw new Error('The function for edit does not support two arguments (data, callback)'); this.moving = true; this.start(); } @@ -524,11 +534,11 @@ exports._editNode = function() { }); } else { - throw new Error(this.constants.labels["editError"]); + throw new Error('The function for edit does not support two arguments (data, callback)'); } } else { - throw new Error(this.constants.labels["editBoundError"]); + throw new Error('No edit function has been bound to this button'); } }; @@ -558,7 +568,7 @@ exports._deleteSelected = function() { }); } else { - throw new Error(this.constants.labels["deleteError"]) + throw new Error('The function for delete does not support two arguments (data, callback)') } } else { @@ -570,7 +580,7 @@ exports._deleteSelected = function() { } } else { - alert(this.constants.labels["deleteClusterError"]); + alert(this.constants.locales[this.constants.locale]["deleteClusterError"]); } } };